繁体   English   中英

驻留在远程JVM中的对象的JDI镜像的寿命

[英]Life-span of JDI mirrors of objects living in a remote JVM

我一直在编写一个Java客户端,该客户端使用JDI在远程JVM中创建和修改对象(通过连接到在远程JVM中运行的基于JDWP代理的服务器)。 我的项目的要求之一是,我不能挂起远程JVM中的所有线程,这意味着我创建的对象在使它们在JVM中可访问之前,很容易受到垃圾回收的影响。

在某些情况下,我正在远程JVM中创建对象,但是会随机对其进行垃圾收集。 例如,如果我通过ArrayType.newInstance(int)在远程JVM中创建一个数组,有时在我可以使它从远程JVM中的另一个可访问对象“可访问”之前,将对其进行垃圾回收。

例如,如果我尝试将新数组存储到现有可达对象的字段中,则对ObjectReference.setValue(Field, Value)的调用可能会随机抛出ObjectCollectedException ):

void createAndStoreArray(ObjectReference reachableObj, Field fieldOfObj, ArrayType type, int length)
{
    ArrayReference ref = type.newInstance(length);
    reachableObj.setValue(fieldOfObj, ref); // Sometimes throws ObjectCollectedException because ref's mirror garbage gets collected before I can store it on the reachable object
}

从理论上讲,在我可以调用ObjectReference.disableCollection()之前, ObjectReference的镜像甚至可能会被垃圾回收ObjectReference.disableCollection()无论如何,出于其他原因,我不想采取此步骤)。

所以我的问题是 ,是否有任何关于JDI Value的书面寿命保证?

  • 远程JVM中的GC是否可以免除原始值的镜像? (一个假设是,但是VirtualMachine . mirror*()方法文档什么也没说。)
  • 字符串镜像是否可以从GC中豁免? (可能不会,但JavaDoc似乎保持沉默。)
  • 我假设可以在任何时候对其他任何ObjectReference进行GC,除非您之前设法禁用了它?

在此先感谢您的帮助!

尽管我找不到从我想要的角度来解决问题的任何文档,但是结合使用GrepCode上的com.sun.tools.jdi包的源代码和Oracle网站上JDWP协议规范,我得出以下结论: :

  1. “镜像”原始值永远不会消失,因为整个原始值都存在于JDI客户端中,直到需要使用JDWP协议将其传输到服务器为止。 在任何情况下,保持仅存在于服务器中的原始值的句柄没有任何优势,因为通过传输发送句柄将花费与发送原始值一样多或更多的字节。 !
  2. 任何引用类型的镜像,包括对VirtualMachine.mirrorOf(String)创建的String的引用,都可以在任何时间进行垃圾回收。

作为对#1的支持,例如,请参见com.sun.tools.jdi.VirtualMachineImpl.mirrorOf(long)的源:它仅实例化LongValueImpl的新实例并返回:

public LongValue mirrorOf(long value) {
    validateVM();
    return new LongValueImpl(this,value);
}

并且您可以看到LongValueImpl的构造函数或其任何超类的构造函数一直到MirrorImpl都没有做任何会通过JDWP传输传输数据并因此更改服务器JVM状态的事情。

与#2对比。 JDI JavaDoc的出发点是任何ObjectReference的镜像对象都可以在任何时间进行垃圾回收:

上的任何方法ObjectReference或直接或间接花费ObjectReference作为参数可能抛出ObjectCollectedException如果镜像对象是否已垃圾收集。

com.sun.tools.jdi.VirtualMachineImpl.mirrorOf(String)的源证实了这一点,它与服务器中的JDWP代理通信。 这只是确认,像任何ObjectReference一样,以这种方式创建的StringReference随时可能受到GC的影响,包括立即...

public StringReference mirrorOf(String value) {
    validateVM();
    try {
        return (StringReference)JDWP.VirtualMachine.CreateString.
            process(vm, value).stringObject;
    } catch (JDWPException exc) {
        throw exc.toJDIException();
    }
}

据我所知,如果根本没有任何ObjectReference ,除非远程JVM中的所有线程都被挂起,否则您需要在捕获ObjectCollectedException的循环中保护与远程JVM中的镜像对象进行交互的所有尝试。 例如,如果您的JDI客户端中有一个方法可以在远程JVM中创建一个String并返回一个不可回收的引用,则可以按照以下方式进行操作:

StringReference safeStringRef(VirtualMachine vm, String string) {
    ObjectCollectedException lastCause = null;
    for (int numTries = 0; numTries < SANE_TRY_LIMIT; ++numTries) {
        StringReference stringRef = vm.mirrorOf(string);
        try {
            stringRef.disableCollection();
            return stringRef;
        } catch (ObjectCollectedException e) {
            lastCause = e;
        }
    }
    throw new RuntimeException("Can't create safe string reference", lastCause);
}

可能对您有用的一件事是ObjectReference.disableCollection() ,它指示已调试的JVM从不收集该对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM