如果允许JVM在垃圾收集期间移动堆内存,那么垃圾收集如何不因移动指针而导致JNI爆炸?
Posted
技术标签:
【中文标题】如果允许JVM在垃圾收集期间移动堆内存,那么垃圾收集如何不因移动指针而导致JNI爆炸?【英文标题】:If JVM is allowed to move heap memory during garbage collect then how does garbage collection not cause JNI to explode due to moving pointers? 【发布时间】:2016-02-16 20:49:15 【问题描述】:使用 ByteBuffer 就是一个例子;将数据从 Array 或 HeapByteBuffer 复制到 DirectByteBuffer 会执行 JNI 调用。
基本上这个...
public static void copyFromByteArray(byte[] src, long srcPos, long dstAddr, long length)
long offset = arrayBaseOffset + srcPos;
while (length > 0)
long size = (length > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : length;
unsafe.copyMemory(src, offset, null, dstAddr, size);
length -= size;
offset += size;
dstAddr += size;
它使用了计算堆指针并直接从堆中复制的魔法。如果该指针在此例程中变得无效,这怎么可能是远程安全的?
对于相关人员:UNSAFE_COPY_THRESHOLD 为 1GB
编辑:感谢您的回复。我正在为寻找同一问题答案的任何人添加以下参考。这个过程使用了安全点(我不知道他们叫什么,所以我不能只是谷歌它)。
参考文献:
http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html http://chriskirk.blogspot.com/2013/09/what-is-java-safepoint.html【问题讨论】:
【参考方案1】:GC 必须强制所有线程进入安全点以移动对象。这意味着所有线程都在已知状态下挂起,以便可以安全地更新所有引用。
在这种情况下,不安全操作是编译器固有的,这意味着您实际上并没有进行调用,而是 VM 插入了实现该功能的机器代码。由于该位置不是安全点,因此该位置可能不会发生 GC。如果需要进行 GC,则 GC 将被推迟,直到执行不安全操作的线程完成此操作并达到这样的安全点。
【讨论】:
unsafe.copyMemory 是一个 JNI 调用。 C 代码不安全且无锁。它通过将对象转换为 (uintptr_t) 并直接从本机内存地址复制来工作。这是否意味着所有 JNI 命令 = 不安全状态?我正在努力更好地了解我可以摆脱什么。 不回答问题。您可以强制将 JNI 方法放入您喜欢的所有安全点,但之后它仍将具有未更改值的直接对象指针。这个答案不能确定正确的机制。【参考方案2】:所有传递给 JNI 方法或由 JNI 方法获取或创建的 Java 对象都将被冻结以用于 GC,直到该方法返回。这就是他们数量有限的原因。
【讨论】:
我关心的是java对象的内存地址,而不是指针。 (基本上是你能做的最不安全的事情)以上是关于如果允许JVM在垃圾收集期间移动堆内存,那么垃圾收集如何不因移动指针而导致JNI爆炸?的主要内容,如果未能解决你的问题,请参考以下文章