The end of minimum / maximum heap size?

One of my various internetty friends (who codes in Flash and Blitz) recently had a rant at me about the fact that Java still has a maximum heap size. I found myself trying to justify it for a little bit, but in fairly short order I realised it was indeed a pointless PITA and probably more of an anachronism as a result of the old garbage collection found in Java 1.0.

Just in case I’m missing something, can anybody tell me again why we need -Xmx / -Xms parameters any more?

Cas :slight_smile:

to limit the resource usage - but then it should be the other way around (default to max usage, limit with options). but yes, it sucks - but so does flash :wink:

By limiting resource usages you protect the OS from hogging it. Such cases can easily happen in Windows. It also happens on Linux but is less vulnerable. But I guess that the VM could monitor this type of issue and protect the OS and hardware then?

Always seemed abit hacky - surely it must be possible to provide some kind of programmatic way of resizing the heap at runtime?
It would then be trivial to make it a privileged action restricted to signed apps.

the VM reserves the memory in a big not fragmented chunk. This enables some GC and memory management optimizations. You probably already heard the VM is sometimes able to get free memory faster than you can do it in C with malloc… at least James Gosling says that in almost every interview :wink:

There is absolutely no reason whatsoever that I can think of that I would want to limit the resources allocated by a Java application. Unsigned applet maybe*, but not application. As a user, when I’ve got free RAM and my application wants it, I expect it to be given, not to throw an OOME!!

As for fragmentation - that’s clearly not the issue, because it starts off small and allocates more anyway, up to whatever pointless arbitrary maximum is set.

Cas :slight_smile:

  • And then I’d also want to be able to limit the amount of CPU and other system resources it can create like threads and sockets too but that’s another story

I experienced that so much time at work in Win XP. When my app server takes the maximum of available memory, windows and the other apps become so unresponsive. That’s because virtual memory is used a lot and is way much slower to manage. So yes a memory limit must be set. I totally agree that it should be managed by the VM.

But that’s basically not “smart”. When a program needs RAM, and there’s RAM available, a normal program just gets it. Why should a Java application be any different? I mean, if you want to put this arbitrary restriction in, that’s great, you can keep it, but the rest of us don’t want it, I think.

Cas :slight_smile:

It might be true that allocating is faster, but I also heard deallocating is slower (because the GC tries to defrag memory?). Even more so when the heap grows bigger and bigger, which all programs seem to do in java if you give them enough time.
TBH in some cases wish I could manually free objects and have no max heap size, but perhaps that’s blasphemy ;D

It would be nice if for example the max heap size would only be a hint and it could grow bigger if needed. Maybe the GC could then just work harder to get the heap size below the max heap size again. But I’m no GC expert…

A programmatic heap resizing strategy would be nice, which could be for example made so that requesting memory beyond max heap would not result in a OOME (but do a full GC or something afterwards):
System.getGC().setHeapSizingStrategy(HeapSizingStrategy hss);

Cas, I’m just trying to explain the reasons to the memory limits the VM impose. I’m not saying I’m happy with the it’s functioning.

I suspect it dates back to legacy internal issues now, rather than any sort of deliberate design decision. Memory allocators are a right pain to write, if you can gurantee that you’re only going to be working inside a fixed, linear, block of memory (ie. allocated up front) then you can do all sorts of extra tricks you couldn’t before (like using the high bits to index into your internal structures so that looking up which pool/sector any given address corresponds to is lightning quick).

However these are not insurmountable issues, and certainly not something that Sun couldn’t work around given the large amount of resources they seem to throw at garbage collectors. It’s an annoying limitation and it really needs to vanish.

* Orangy Tang has been debugging someone else’s C memory allocator over the last few days, and is sick of it.

was probably referring to http://www.ibm.com/developerworks/java/library/j-jtp09275.html

Remember that the GC has one biiiiig advantage over conventional malloc/free memory manages - it can actually move allocated blocks and objects around in memory as it sees fit. Dealing with fragmentation in a malloc/free memory manager means either using fixed sized blocks (wasteful) or dynamically sized blocks (lots of extra overhead to store and manage, plus you need complicated logic to merge adjacent blocks as they become available). Often you end up with a combination of the two (a variety of fixed size pools for small allocations, dynamically sized blocks for larger allocations). Contrast with Java where since there’s no direct memory/pointer access you can relocate objects at will and fragmentation becomes a much smaller problem.

Without a limit, when would the JVM decide when to run a full GC ?

Typically when you need lots of RAM, you’ll be working with large arrays/buffers. With Unsafe, you can malloc without any restriction, and change a *Buffer object’s base (pointer) field. So for applications like 3D games, the heap limit doesn’t really have to be a problem. You just shouldn’t be afraid to write your own memory-management… ugh

That wouldn’t need to change: I think full GC’s are started when the heap needs resizing, not necessarily when the max heap size is filled.

zackly. My thoughts are currently that the only parameter that really matters here is the throughput of the GC - that is, the application merely has to meet its performance specifications, and size its heap and garbage collections accordingly. So if I specified -XX:MaxGCTimeMillis=1 then the heap would get sized to whatever it needed to be to get that performance with the absolute minimum amount of allocated RAM. Not forgetting the old generation is only half of the story; the eden and young generation and survivor spaces can also all twiddle around automatically.

Cas :slight_smile:

well, I really miss the motivation in having a automatically adapting xmx. Why do we need it?

When you are developing applications running on servers you will almost always set the -Xmx to the available memory. When you are on the desktop you almost always deal with easy to predict applications regards memory consumption.
(I can’t remember when I got the last time an out of memory exception in eclipse or netbeans and this kind of (modular) apps are really not easy to predict…just open 120 projects. On netbeans you will even get a nice warning dialog notifying you about to few memory _before you get out of memory exceptions)

If it is not possible for some reason to estimate the memory consumption of an applet or similar apps, just set the -Xms to 512m or more. This is probably exactly what you want. The heap starts with xms and will grow until max is reached and when it is reached something is probably wrong with your applet :wink:

maybe I overlooked an essential usecase.

In general I think -xmx doesn’t serve the user or developer, I suspect it’s mostly there because of legacy.
It’s not that I want it adapting, I want it not to exist (unless specifically set for security reasons).

Right. What happens right now is, if you forget to twiddle the value, you get an OOME and the program generally crashes with a long period of 100% CPU just beforehand - hardly a great user experience. I’ve had this happen before with Eclipse, and some image processing utilities. It’s a very poor user experience.

However…

setting -Xmx2g isn’t the best solution either because then the VM happily seems to gobble up all the RAM it can and never shrinks it again. I suspect because it has a happy free instruction to just use that amount of RAM, it does so, and never bothers trying to be frugal with it. That’s where the throughput parameter should come in, to help it decide just how much time it can spend garbage collecting.

Cas :slight_smile:

[quote]setting -Xmx2g isn’t the best solution either because then the VM happily seems to gobble up all the RAM it can and never shrinks it again. I suspect because it has a happy free instruction to just use that amount of RAM, it does so, and never bothers trying to be frugal with it.
[/quote]
Actually, I just did a simple GC stress test (allocateing a random number of bytes in a loop), and it didn’t really matter to what value I set -Xmx: the average memory consumption stayed the same, even when I set -Xmx to 2Gb. It seems the GC shrinks the heap as advertised.

All the more reason -Xmx should be unlimited unless specified, or sandboxed :slight_smile: