Re: Ranting about JVM's default memory limits...
 
Lew <noone@invalid.com> wrote:
In the process of copying live references from one young-generation 
space to the other, the heap is automatically compacted.
Peter Duniho wrote:
What happens as objects are eventually removed from an older-generation 
space?
Presumably some explicit compaction has to happen _somewhere_.
I don't know, but it's less of a problem for old-generation because allocation 
doesn't happen there.  Some googling should give you that answer quickly.
..NET achieves the same thing simply by putting compaction off until 
it's really needed.
It's why it's better to use short-lived objects in Java programs.
In .NET, the memory manager simply keeps track of the boundary between 
the generations (if I recall correctly, the current implementation has 
just two generations: young and old).  Either generation can become 
fragmented, but what normally happens is that at the same time the young 
generation is collected, anything left winds up in the old generation by 
virtue of the boundary pointer being moved.  So the old generation 
inherits whatever fragmentation existed in the young generation.
Things don't move from young to tenured in Java until they have been through 
several minor collections.
The tenured generation is a completely separate space from the young 
generation.  The "boundary pointer" doesn't move.
It surprises me to hear that Java's implementation isn't similar.  
Not me.
Certainly there's an automatic compaction that would occur if references 
actually are _copied_ from one generation to another, but that comes at 
a cost: the memory manager is effectively required to compact with 
_every_ collection that updates the generations (and presumably that's 
every collection?).  And no matter when compaction is happening (during 
all collections or less frequently, on an "as-needed" basis), it's 
expensive both because of all the data that has to be touched, and 
because it requires threads to be suspended so that their references can 
all be updated.
I don't know if this happens in the old generation in Java.  Compaction 
happens by the copy from one young space to the other in the young generation. 
  Since short-lived objects tend to dominate, being around 95-98% of objects 
in most programs according to what I've read, not a whole lot need be copied. 
  It can be made worse by needlessly hanging on to objects in Java.
If Java's really doing all that work with every collection, I guess I 
can see how the GC implementation in Java would have trouble any time 
any significant number of objects ages out of the young generation, 
since that would significantly increase the cost of each collection 
operation.
That is a strong case for keeping objects short-lived in Java.  Thus it is 
better to use:
  for ( Foo foo : foos )
  {
    Bar bar = new Bar( foo );
   ...
  }
than
  Bar bar = new Bar();
  for ( Foo foo : foos )
  {
    bar.init( foo );
   ...
  }
(assuming the state of a Bar is the same after 'new Bar(foo)' or 'init(foo)')
-- 
Lew