RFR: 8205683: Refactor heap allocation to separate concerns
Per Liden
per.liden at oracle.com
Wed Jun 27 10:43:38 UTC 2018
Hi Erik,
On 06/26/2018 05:13 PM, Erik Österlund wrote:
> Hi,
>
> After a bunch of stuff was added to the CollectedHeap object allocation
> path, it is starting to look quite ugly. It has function pointers passed
> around with arguments to be sent to them, mixing up allocation,
> initialization, tracing, sampling and exception handling all over the
> place.
>
> I propose to improve the situation by having an abstract MemAllocator
> stack object own the allocation path, with suitable subclasses,
> ObjAllocator, ClassAllocator and ObjArrayAllocator for allocating the 3
> types we support allocating on the heap. Variation points now simply use
> virtual calls, and most of the tracing/sampling code can be moved out
> from the allocation path. This should make it easier to understand what
> is going on here, and the different concerns are more separated.
>
> A collector can override the virtual member functions for allocating
> objects, arrays, and classes, and inject their own variation points into
> this framework. For example for installing a forwarding pointer in the
> cell header required by Brooks pointers, if you are into that kind of
> stuff.
>
> Bug:
> https://bugs.openjdk.java.net/browse/JDK-8205683
>
> Webrev:
> http://cr.openjdk.java.net/~eosterlund/8205683/webrev.02/
Awesome cleanup Erik! A few comments/questions/suggestions:
src/hotspot/share/gc/shared/collectedHeap.cpp
---------------------------------------------
449 oop CollectedHeap::obj_allocate(Klass* klass, int size, TRAPS) {
450 ObjAllocator allocator(klass, size);
451 return allocator.allocate();
452 }
453
454 oop CollectedHeap::array_allocate(Klass* klass, int size, int
length, bool do_zero, TRAPS) {
455 ObjArrayAllocator allocator(klass, size, length, do_zero);
456 return allocator.allocate();
457 }
458
459 oop CollectedHeap::class_allocate(Klass* klass, int size, TRAPS) {
460 ClassAllocator allocator(klass, size);
461 return allocator.allocate();
462 }
I doesn't look like the above functions need to take in TRAPS, right?
src/hotspot/share/gc/shared/memAllocator.hpp
--------------------------------------------
47 HeapWord* allocate_from_tlab(Allocation& allocation) const;
48 HeapWord* allocate_from_tlab_slow(Allocation& allocation) const;
49 HeapWord* allocate_outside_tlab(Allocation& allocation) const;
Can we call these allocate_inside_tlab/allocate_outside_tlab?
73 virtual oop init_obj(HeapWord* mem) const;
Can we call this initialize() instead? To better line up with allocate().
Further, I'd also like to see initialize() being a pure virtual function
and instead do what that function does today in a different function,
protected and non-virtual, called finish(). So in the end we'll have:
allocate();
initialize();
finish();
I believe such naming/structure would make code like this easier to
understand:
src/hotspot/share/gc/shared/memAllocator.cpp:
415 mem_clear(mem);
416 java_lang_Class::set_oop_size(mem, (int)_word_size);
417 oop obj = finish(mem);
Otherwise, calling init_obj()/initialize() as the last thing here seems
a bit odd and suggests the we're re-initializing the object completely.
src/hotspot/share/gc/shared/memAllocator.cpp
--------------------------------------------
...
391 oop obj = MemAllocator::init_obj(mem);
392 assert(Universe::is_bootstrapping() || !obj->is_array(), "must not
be an array");
393 return obj;
394 }
...
405 oop obj = MemAllocator::init_obj(mem);
406 assert(obj->is_array(), "must be an array");
407 return obj;
408 }
...
417 oop obj = MemAllocator::init_obj(mem);
418 assert(Universe::is_bootstrapping() || !obj->is_array(), "must not
be an array");
419 return obj;
420 }
The above asserts look unnecessary. If so, it would be nice to just
convert this to:
...
391 return finish(mem);
392 }
...
405 return finish(mem);
406 }
...
417 return finish(mem);
418 }
200 HeapWord* mem = (HeapWord*)obj;
201 size_t size_in_bytes = _allocator._word_size * HeapWordSize;
202 ThreadLocalAllocBuffer& tlab = _thread->tlab();
203 size_t bytes_since_last = _allocated_outside_tlab ? 0 :
tlab.bytes_since_last_sample_point();
204 _thread->heap_sampler().check_for_sampling(mem, size_in_bytes,
bytes_since_last);
Looks like we can now change the first arg in check_for_sampling() from
HeapWord* to oop and avoid the casting above and inside
check_for_sampling() itself.
src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp
------------------------------------------------------
143 HeapWord* allocate_sampled_object(size_t size);
Can we call this function allocate_sampled() to better match with
allocate()?
cheers,
Per
More information about the hotspot-gc-dev
mailing list