【问题标题】:GC.AddMemoryPressure equivalent in JavaJava 中的 GC.AddMemoryPressure 等价物
【发布时间】:2011-10-06 16:36:16
【问题描述】:

项目:Java、JNI (C++)、Android。

我将通过创建一个托管包装类来管理本机 C++ 对象的生命周期,该类将保存一个指向本机对象的指针(作为长成员),并将在其被覆盖的 finalize() 方法中删除本机对象。详情请见this question

C++ 对象不消耗其他类型的资源,只消耗内存。对象的内存占用不是很高,但本质上高于Java中的64位长。有没有办法告诉 Java 的 GC,我的包装器不仅负责一个 long 值,而且在运行垃圾收集之前创建数百万个这样的对象不是一个好主意?在 .NET 中有一个 GC 的 AddMemoryPressure() 方法,正是为了这个目的。 Java中是否有等价物?

【问题讨论】:

  • 由于在 Java 中 JNI 是非常规的例外,而在 C# 中它非常重要 - 不,据我所知没有办法做到这一点。

标签: java memory-management garbage-collection java-native-interface


【解决方案1】:

经过一番谷歌搜索,我找到了来自 IBM 研究中心的 good article

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

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

【讨论】:

  • 复活这个非常古老的答案...如果 GetByteArrayElements 总是返回副本怎么办?然后你最终,内存消耗加倍......加上返回的数组(通过 GetByteArrayElements)将不会被 GC 感知。因此,在调用终结器之前,您将耗尽内存。
【解决方案2】:

我相信本机内存是在 Java 堆大小范围之外分配的。这意味着,您不必担心您的分配会占用您使用 -Xmx<size> 保留的值。

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

【讨论】:

    猜你喜欢
    • 2019-11-03
    • 2016-07-16
    • 2010-09-08
    • 2012-05-09
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 2013-01-15
    相关资源
    最近更新 更多