RFR: 8055702 - Remove the generations array

Jesper Wilhelmsson jesper.wilhelmsson at oracle.com
Fri Oct 17 12:25:07 UTC 2014


Hi Kim!

Thanks for looking at this change!

This cleanup is followed by five more found in the review thread "RFR: 8057632 - 
Remove auxiliary code used to handle the generations array"

I chose to split this rather large cleanup into several pieces to make it easier 
to review it. So, if you are OK with a few intermediate versions of less beauty, 
I would prefer to read your comments in the light of the last version after all 
cleanups have been made.

A new webrev is available here that fixes the java code mentioned below:
http://cr.openjdk.java.net/~jwilhelm/8055702/webrev.01/

See comments inline.

Kim Barrett skrev 16/10/14 23:39:
> On Oct 14, 2014, at 9:28 AM, Jesper Wilhelmsson <jesper.wilhelmsson at oracle.com> wrote:
>>
>> Hi all,
>>
>> Resurrecting this thread from the past.
>> I got one review from Mikael, need another to clean this up.
>>
>> Thanks!
>> /Jesper
>>
>>
>> Jesper Wilhelmsson skrev 22/8/14 15:20:
>>> […]
>>> Webrev: http://cr.openjdk.java.net/~jwilhelm/8055702/webrev/
>>>
>>> Bug: https://bugs.openjdk.java.net/browse/JDK-8055702
>
> ==============================================================================
> agent/src/share/classes/sun/jvm/hotspot/memory/GenCollectedHeap.java
>   77     if ((i < 0) || (i >= nGens())) {
>   78       return null;
>   79     }
>   80
>   81     if (i == 0) {
>   82       return genFactory.newObject(youngGenField.getAddress());
>   83     } else {
>   84       return genFactory.newObject(oldGenField.getAddress());
>   85     }
>
> Most of the java code seems to still be agnostic about the number of
> generations.  This is the one place where the limit of 2 generations
> is being hard-wired.  I think it would be appropriate to protect this
> code with some sort of check that nGens() < 2.
>
> Optionally, I think it would now be simpler to merge the two if
> statements into a single switch statement, e.g.
>
>     switch (i) {
>     case 0:
>         return genFactory.newObject(youngGenfield.getAddress());
>     case 1:
>         return genFactory.newObject(oldGenfield.getAddress());
>     default:
>         // no generation for i, and assertions disabled.
>         return null;
>     }
>
> [Of course, leave the line 72-75 assertion in place.]
>

I like the switch so I'm using it as suggested.

> ==============================================================================
> src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
> 957         prev_size = prev_gen->capacity();
> 958           gclog_or_tty->print_cr("  Younger gen size "SIZE_FORMAT,
> 959                                  prev_size/1000);
>
> The logging statement at 958 appears to be mis-indented.
> [Pre-existing problem.]
>

This is fixed in one of the later cleanups.

> ==============================================================================
> src/share/vm/memory/genCollectedHeap.cpp
> 141   ReservedSpace young_rs = heap_rs.first_part(_gen_specs[0]->max_size(), false, false);
> 142   _young_gen = _gen_specs[0]->init(young_rs, 0, rem_set());
> 143   heap_rs = heap_rs.last_part(_gen_specs[0]->max_size());
> 144
> 145   ReservedSpace old_rs = heap_rs.first_part(_gen_specs[1]->max_size(), false, false);
> 146   _old_gen = _gen_specs[1]->init(old_rs, 1, rem_set());
> 147   heap_rs = heap_rs.last_part(_gen_specs[1]->max_size());
>
> Could we have a helper function for this near duplicated code?
>
> There's a bunch of hard-coded 0s and 1s here for young and old
> respectively.
>
> This also makes me wonder if _gen_specs[] should also be eliminated;
> it looks like it was a parallel array to the _gens[] array, with the
> latter being no longer present.
>

I wrote the code in this way deliberately to make it easy to review, 
_gen_specs[] is going away in a later cleanup, so are all 0s and 1s. The final 
version of this code looks as follows:

   ReservedSpace young_rs = 
heap_rs.first_part(gen_policy()->young_gen_spec()->max_size(), false, false);
   _young_gen = gen_policy()->young_gen_spec()->init(young_rs, rem_set());
   heap_rs = heap_rs.last_part(gen_policy()->young_gen_spec()->max_size());

   ReservedSpace old_rs = 
heap_rs.first_part(gen_policy()->old_gen_spec()->max_size(), false, false);
   _old_gen = gen_policy()->old_gen_spec()->init(old_rs, rem_set());
   heap_rs = heap_rs.last_part(gen_policy()->old_gen_spec()->max_size());

There are a lot of similarities between the young and old handling here but 
personally I don't see a benefit in breaking this code out into a helper function.

> 234 void GenCollectedHeap::save_used_regions(int level) {
> 235   assert(level < _n_gens, "Illegal level parameter");
> 236   if (level == 1) {
> 237     _old_gen->save_used_region();
> 238   }
> 239   _young_gen->save_used_region();
> 240 }
>
> More hard-coded 0s (implicit) and 1s here for young and old
> respectively.
>

All hard coded 0s and 1s are going away in one of the following cleanups.

> I looked at the changes to do_collection() involved in factoring out
> new collect_generation().  I *think* they are ok, but it's hard to be
> sure because the webrev diffs are a bit of a mess.  It might be easier
> to review if collect_generation() followed do_collection() rather than
> preceeding it.  [Of course, making that change would make a mess of an
> incremental webrev.]
>

Do you have access to a slightly more advanced diff tool like Beyond Compare for 
instance? (Free demo version available online.)  With that tool you can choose 
which lines to align and diff this part more easily.

> ==============================================================================
> src/share/vm/memory/genCollectedHeap.hpp
> 373   Generation* prev_gen(Generation* gen) const {
> 374     int l = gen->level();
> 375     guarantee(l == 1, "Out of bounds");
> 376     return _young_gen;
> 377   }
> 378
> 379   // Return the generation after "gen".
> 380   Generation* next_gen(Generation* gen) const {
> 381     int l = gen->level() + 1;
> 382     guarantee(l == 1, "Out of bounds");
> 383     return _old_gen;
> 384   }
> 385
> 386   Generation* get_gen(int i) const {
> 387     guarantee(i >= 0 && i < _n_gens, "Out of bounds");
> 388     if (i == 0) return _young_gen;
> 389     else return _old_gen;
> 390   }
>
> Suggest changing next_gen() to
>
>   Generation* next_gen(Generation* gen) const {
>     int l = gen->level();
>     guarantee(l == 0, "Out of bounds");
>     return _old_gen;
>   }
>
> to eliminate the +1 and be more consistent with prev_gen().
>
> Oh, but maybe this doesn't matter.  I just re-read the webrev request
> and see that get_gen(), next_gen(), and prev_gen() are slated to go
> away.
>
> Again here, many hard-coded 0s and 1s for young and old respectively.
>
> BTW, "l" (lowercase L) and "1" (integer one) look *very* similarly in
> some fonts, making "l" (lowercase L) a poor choice of variable name.
> I had to look really closely at the webrev to see that "l == 1" was
> not tautological.  Similar issue with "O" (capital o) and 0 (integer
> zero).
>

Yes, these three are going away in one of the later cleanups.

> ==============================================================================
> src/share/vm/memory/genMarkSweep.cpp
> 161   // Scratch request on behalf of oldest generation; will do no
> 162   // allocation.
> 163   ScratchBlock* scratch = gch->gather_scratch(gch->get_gen(gch->_n_gens-1), 0);
>
> Why not "gch->old_gen()" instead of "gch->get_gen(gch->_n_gens-1)" ?
>

In this change I tried to remove the generations array without changing too much 
other code in order to make it easier to review it. All cleanups enabled by this 
change has been performed in later changes (I hope). In this particular case 
old_gen() is used in the final version as suggested.

> ==============================================================================
> src/share/vm/memory/generation.cpp
> 162 Generation* Generation::next_gen() const {
> 163   GenCollectedHeap* gch = GenCollectedHeap::heap();
> 164   int next = level() + 1;
> 165   if (next < gch->_n_gens) {
> 166     return gch->get_gen(next);
> 167   } else {
> 168     return NULL;
> 169   }
> 170 }
>
> Perhaps instead
>
> Generation* Generation::next_gen() const {
>   GenCollectedHeap* gch = GenCollectedHeap::heap();
>   if (this == gch->young_gen()) {
>     return gch->old_gen();
>   } else {
>     assert(this == gch->old_gen());
>     return NULL;
>   }
> }
>
> But again here, maybe this next_gen() is also slated to go away?
>

Yes, next_gen() is also removed in one of the later cleanups.

> ==============================================================================
> src/share/vm/runtime/vmStructs.cpp
> 547     static_field(GenCollectedHeap,             _gch,                                          GenCollectedHeap*)                     \
> 548  nonstatic_field(GenCollectedHeap,             _n_gens,                                       int)                                   \
>
> These two lines appear to be incorrectly indented wrto the surrounding
> parts of this file.
>

_n_gens is going away, but _gch stays and was actually still one space off. I 
fixed that now in the last cleanup change. I'll upload a new webrev and ping the 
other mail thread about that.

> ==============================================================================
>

Thanks!
/Jesper


More information about the hotspot-gc-dev mailing list