OutOfMemory Exception
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Jan 23 11:27:57 UTC 2023
On 23/01/2023 11:21, Martin Pernollet wrote:
> Thank you once again for your prompt reply! I fixed thanks to your
> advices.
>
> In the my previous version on JDK17, the culprit loop was invoking
> ResourceScope.newImplicit() any time a memory segment was required,
> without keeping the created scope instance. I was not calling
> scope.close() neither segment.unload() and everything was fine.
> When upgrading to JDK19 I made the MemorySession (formerly
> ResourceScope) shared by all calls to the culprit loop at the instance
> level. I assume that doing this change prevent the MemorySession being
> collected by the GC, leading to all MemorySegment to stay in memory.
Yes, this was indeed the likely culprit.
>
> My conclusion is that the best approach with frequent exchanges
> between the java program and the OpenGL library is to create implicit
> sessions for the shortest possible time.
Or, if you know the start/end of your lifetimes, just use a confined
session:
```
try (MemorySession session = MemorySession.openConfined()) {
MemorySegment segment = session.allocate(...);
...
} // memory deallocated exactly here
```
The above idiom leaves no room for guesswork as to _when_ memory will be
deallocated.
>
> Re-reading your documentation, I wonder if it is better to use instead
> SegmentScope.auto() ?
In the 20 API, MemorySession.openImplicit has been replaced with
SegmentScope.auto() - but the functionality is the same.
If you want optimal native memory usage, I think you'd have to try to
see if you can come up with a definition of where the boundaries of your
native allocations are.
(Btw, I'm in the process of sharing a document/writeup on lifetimes,
which might help understanding what are the memory management options
provided by the FFM API, stay tuned).
Cheers
Maurizio
>
> Cheers,
>
> Martin
>
> ------- Original Message -------
> Le lundi 23 janvier 2023 à 11:19, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com> a écrit :
>
>> Hi Martin,
>> the OOM you are getting is not a Java heap OOM. It is caused by the
>> default limit set for off-heap memory. This is controlled by the same
>> option used for increasing memory available for direct byte buffer
>> (hence the exception message), namely:
>>
>> -XX:MaxDirectMemorySize=<size>
>>
>> For this reason, I doubt that what you see on VisualVM correlates
>> with the exception you are seeing (in fact the seesaw pattern you
>> attached seems to show that on-heap memory usage is quite stable).
>>
>> As to the actual causes, if your application is using
>> openConfined/openShared (w/o a cleaner parameter!), then, assuming it
>> still calls "MemorySession::close" in the same places where it did in
>> 17, nothing should have changed (in fact, the underlying
>> implementation between 17 and 19 did not change much at all). In that
>> case, all the memory segments associated with the session have their
>> off-heap memory deallocated when the session is closed.
>>
>> If you are using openImplicit, or openConfined/Shared (with a cleaner
>> parameter!) then you are at the mercy of the GC - which means that
>> you should make sure that the implicit session containing no-longer
>> needed data is truly unreachable from within your application.
>>
>>> I can not unload() the MemorySegment when I am done using it (but
>>> this was also not possible in JDK17).
>>
>> You can - but you have to plan ahead - e.g. if you need to allocate a
>> bunch of segments, then do something with them, and then free them -
>> then you need a temporary session where to allocate those segments,
>> and use a try-with-resource on the temp session object.
>>
>> Maurizio
>>
>> On 22/01/2023 17:09, Martin Pernollet wrote:
>>> Hi,
>>>
>>> After switching PanamaGL from JDK17 to JDK19, I am facing an
>>> OutOfMemory exception.
>>>
>>> The part where this occurs is in the loop that performs offscreen
>>> rendering and then copy the result to a BufferedImage later used for
>>> onscreen rendering.
>>>
>>> This allocation
>>>
>>> intnBytes=width*height*channels;
>>>
>>> MemorySegmentpixelsRead=MemorySegment.allocateNative(nBytes,scope);
>>>
>>> gl.glReadPixels(0,0,width,height,format,textureType,pixelsRead);
>>>
>>> Fails as follow
>>>
>>> java.lang.OutOfMemoryError: Cannot reserve 2169600 bytes of direct
>>> buffer memory (allocated: 4293080163, limit: 4294967296)
>>>
>>> at java.base/java.nio.Bits.reserveMemory(Bits.java:178)
>>>
>>> at java.base/java.nio.Buffer$1.reserveMemory(Buffer.java:860)
>>>
>>> at
>>> java.base/jdk.internal.foreign.NativeMemorySegmentImpl.makeNativeSegment(NativeMemorySegmentImpl.java:122)
>>>
>>> at
>>> java.base/java.lang.foreign.MemorySegment.allocateNative(MemorySegment.java:965)
>>>
>>> at
>>> java.base/java.lang.foreign.MemorySegment.allocateNative(MemorySegment.java:942)
>>>
>>>
>>> As shown on the VisualVM screenshot the heap grows at the beginning
>>> but is then freed. The exception happens when the heap reduces
>>> suddenly on the chart.
>>>
>>> Capture d’écran 2023-01-22 à 17.48.40.png
>>>
>>> The behavior is the same for all possible scopes provided by
>>> MemorySession (global, openConfined, openShared, openImplicit.
>>>
>>> One thing : I can not unload() the MemorySegment when I am done
>>> using it (but this was also not possible in JDK17).
>>>
>>> *How could I track this memory leak? How could I ensure that useless
>>> memory get destroyed?*
>>>
>>> Thanks in advance,
>>>
>>> Martin
>>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20230123/82eb06ff/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Capture d??cran 2023-01-22 ? 17.48.40.png
Type: image/png
Size: 36259 bytes
Desc: not available
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20230123/82eb06ff/Capturedcran2023-01-2217.48.40-0001.png>
More information about the panama-dev
mailing list