RFR: 8247755: Leaner and more versatile GrowableArray classes
Stefan Karlsson
stefan.karlsson at oracle.com
Thu Jun 18 21:20:18 UTC 2020
Hi Coleen,
On 2020-06-18 21:39, coleen.phillimore at oracle.com wrote:
>
> http://cr.openjdk.java.net/~stefank/8247755/webrev.01/src/hotspot/share/utilities/growableArray.cpp.html
>
>
> 92 #endif
>
> nit, can you add // ASSERT here
Sure.
>
>
>
> http://cr.openjdk.java.net/~stefank/8247755/webrev.01/src/hotspot/share/utilities/growableArray.hpp.html
>
>
> 302 template <typename E, typename S>
> 303 class GrowableArrayWithAllocator : public GrowableArrayView<E> {
>
>
> So all the functions in this class need to be able to call grow(),
> with allocator 'S' right?
Yes.
> Can template parameter 'S' be "ALLOC" so it's easy to find?
I chose the name S to match that the class that S represents *must* be a
subclass. I can rename it to ALLOC, but then the name would loose that
connection. I'd like to here more opinions before changing this.
>
> The early tiers run the SA tests so I think if it's not broken your SA
> changes are sufficient.
OK. I'll make sure that they pass.
>
>
> Second webrev.
>
> http://cr.openjdk.java.net/~stefank/8247759/webrev.01/src/hotspot/share/gc/z/zArray.hpp.udiff.html
>
>
> I looked at the diffs and they seemed fine (don't know the code). This
> is a nice result of this rewrite.
Yes. At least I think so. This was the code that made me start
investigating this:
https://cr.openjdk.java.net/~stefank/8247759/webrev.01/src/hotspot/share/gc/z/zPhysicalMemory.cpp.udiff.html
Thanks for looking at the code,
StefanK
>
> Coleen
>
> On 6/17/20 10:16 AM, Stefan Karlsson wrote:
>> Hi all,
>>
>> Please review and/or comment on this patch to create leaner and more
>> versatile GrowableArray classes.
>>
>> https://cr.openjdk.java.net/~stefank/8247755/webrev.01
>> https://bugs.openjdk.java.net/browse/JDK-8247755
>>
>> This is a proposal to rewrite the GrowableArray classes, with two
>> main goals:
>>
>> 1) Allow a GrowableArray instance to be allocated on the stack or
>> embedded in other objects. This removes one of the two indirections
>> when operating on the array elements.
>>
>> 2) Make the GrowableArray instances smaller, so that there's no extra
>> overhead when they are embedded in other objects.
>>
>> This will enable us to use GrowableArray effectively in ZGC, without
>> having to rely on our own implementations. See follow-up patch:
>> https://cr.openjdk.java.net/~stefank/8247759/webrev.01
>>
>> Some background about the GrowableArray:
>>
>> GrowableArray is split into two memory parts. One for the instance of
>> the GrowableArray, and a second, separate memory part for the
>> elements. This memory can come from these places:
>>
>> a) Resource area in the thread
>> b) CHeap (malloc)
>> c) Arena (malloced arena)
>> d) Stack
>> e) Embedded in other object
>>
>> From the C++ compiler's point-of-view, (a)-(e) can be used to
>> allocate the GrowableArray, and (a)-(c) can be used to allocate the
>> elements. However, there are runtime asserts that restricts the
>> combinations.
>>
>> One of the restrictions is that if either of the GrowableArray
>> instance memory, or the elements memory, comes from the CHeap, then
>> the other must also come from the CHeap.
>>
>> I've found two reasons why we want to be restrictive with our CHeap
>> allocated elements:
>>
>> - if the GrowableArray instance is allocated in (a) or (c), then the
>> destructor will never run and we get a memory leak because the
>> elements are not deallocated.
>>
>> However, for stack allocated instances the destructor will be run,
>> and the memory will be handed back. For embedded instances it all
>> depends on how the parent instance was allocated.
>>
>> - There's no proper support for copying/moving of the elements, just
>> a simple pointer copy. So, if a copy would be done, the source
>> GrowableArray would still have a pointer to the elements, and if the
>> source were destructed (maybe because it was stack allocated and went
>> out-of-scope) then the memory of the destination GrowableArray will
>> be deallocated. This isn't a problem with instances in (a) or (c),
>> since their destructors won't be run.
>>
>> Proposal for Goal 1:
>>
>> - Allow stack allocated and embedded GrowableArrays to have CHeap
>> allocated elements.
>> - Add an assert in a copy constructor and assignment operator that
>> checks that the GrowableArray elements are not CHeap allocated.
>>
>> The rest of the patch mainly deals with Goal 2:
>>
>> The current fields of GrowableArrays, in product builds, are:
>> int _len;
>> int _max;
>> Arena* _arena;
>> MEMFLAGS _memflags;
>> E* _data;
>>
>> and the resulting is 32 bytes: 4 + 4 + 8 + 8 + 8. The _memflags size
>> is due to alignment requirements for the _data field.
>>
>> - By combining _arena and _memflags, this is reduced to 24 bytes.
>> - By having a specialized CHeap version with the MEMFLAGS encoded as
>> a template parameter, we can get rid of both _memflags and _arena
>> fields, and reduce this to 16 bytes.
>>
>> Things to note about the patch:
>>
>> - GrowableArrayMetadata: I've fused _arena and _memflags into one
>> uintptr_t field, and encapsulated all bookkeeping about where and how
>> the memory is allocated for the GrowableArray. The hope is to
>> simplify the code a bit, and also to move some of the checking out
>> into a non-template class, so that the code can be put in the .cpp file.
>>
>> - GrowableArrayNestingCheck: Simplify and encapsulate resource area
>> nesting checks.
>>
>> - I'm using CRTP because I don't want a vtable in the class. This
>> means that the super class can cast to derived type, responsible for
>> allocation and deallocation:
>>
>> template <typename E> class GrowableArray : public
>> GrowableArrayWithAllocator<E, GrowableArray<E> >
>>
>> and then:
>>
>> void GrowableArrayWithAllocator<E, S>::grow(int j) {
>> ...
>> E* newData = static_cast<S*>(this)->allocate();
>>
>> - Since I'm chainging so much of the structure of the code, I've also
>> made some stylistic changes to make the code more consistent.
>>
>> - Moved the CompareClosure to iterator.hpp, where many of our other
>> closures are located.
>>
>> - Moved _sort_Fn, since it was already used by non-GrowableArray code
>>
>> - I've added a GrowableArrayCHeap class to be able to mostly
>> side-step the complication of the GrowableArray elements allocation,
>> and to minimize the instance size.
>>
>> - The metaspaceShared.cpp was used to show how GrowableArrayCHeap can
>> be used. It's not strictly necessary, and could be reverted.
>>
>> - The arguments.cpp change shows a usage of GrowableArrayView as a
>> way to only expose an interface that don't allow the array to be grown.
>>
>> - The arguments.cpp change also shows stack allocated
>> GrowableArrayCHeap, that automatically gets deallocated when the
>> function returns, and the cleanups we can do because of this.
>>
>> - The hashtable.* changes show an embedded GrowableArrayCHeap.
>>
>> - The SA agent. I didn't bother renaming the GenericGrowableArray
>> file. I can do that upon request.
>>
>> - I added gtest for GrowableArray. There was not a single unit test
>> of GrowableArray before. The creates all possible memory allocation
>> combinations and run limited set of sanity checks. It also checks
>> that the different memory allocation combinations return the correct
>> allocation types when queried. I've added negative tests to show that
>> GrowableArrays with CHeap allocated elements assert when being copied.
>>
>> Testing: will run at least tier1-3, but most likely more tiers on
>> Linux x64. Suggestions on what to test welcome.
>>
>> Thanks,
>> StefanK
>
More information about the hotspot-dev
mailing list