Java中的GC.AddMemoryPressure等价方法是什么?

9

项目: Java, JNI (C++), Android.

我将通过创建一个托管包装类来管理本地的C++对象生命周期,该类将持有指向本地对象的指针(作为长整型成员)并将在其重写的finalize()方法中删除本地对象。详情请参见此问题

C++对象不消耗其他类型的资源,只占用内存。对象的内存占用量并不是非常高,但它比Java中的64位长整型要高得多。有没有办法告诉Java的GC,我的包装类负责不止一个长整型值,并且在运行垃圾回收之前创建数百万这样的对象不是一个好主意?在.NET中,有一个GC的AddMemoryPressure()方法,专门用于此目的。在Java中是否有类似的方法呢?


由于在Java中JNI非常特殊,而在C#中它非常重要,据我所知没有办法做到这一点。 - Voo
2个回答

7

在进行了更多的搜索后,我找到了一篇来自IBM研究中心的好文章

简而言之,他们建议使用Java堆而不是本地堆来存储本地对象。这样,JVM垃圾回收器上的内存压力对于从Java代码通过句柄引用的本地对象来说更加真实。

为了实现这一点,我们需要重写默认的C ++堆分配和释放函数:operator new和operator delete。在operator new中,如果JVM可用(JNI_OnLoad已经被调用),则可以调用NewByteArray和GetByteArrayElements,它将返回所需的分配内存。为了保护创建的ByteArray不被垃圾回收,还需要创建NewGlobalRef,并将其存储在相同的分配内存块中。在这种情况下,我们需要分配与请求的内存大小相同的内存,以及引用的内存。在operator delete中,我们需要使用DeleteGlobalRef和ReleaseByteArrayElements。如果JVM不可用,则需要使用本地malloc和free函数。


重新激活这个非常古老的答案... 如果 GetByteArrayElements 总是返回副本怎么办?那么你最终会导致内存消耗翻倍... 另外,由 GetByteArrayElements 返回的数组将不会被 GC 感知。因此,在调用 finalizers 之前,您将耗尽内存。 - tower120

1

我相信本地内存是在Java堆大小范围之外分配的。也就是说,您不必担心分配会从使用-Xmx<size>保留的值中占用内存。

话虽如此,您可以使用ByteBuffer.allocateDirect()来分配缓冲区,并使用GetDirectBufferAddress从本地代码中访问它。您可以使用-XX:MaxDirectMemorySize=<size>来控制直接内存堆的大小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接