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