什么是.net的GC.KeepAlive的Java等价物?

时间:2014-03-17 14:28:28

标签: java .net garbage-collection java-native-interface finalizer

.NET有一个名为GC.KeepAlive(Object)的函数。其唯一目的是确保引用对象的生命周期持续到代码流到达调用。

除非有人与本机代码进行互操作,否则通常不需要这样做。

我的情况是,我已经获得了通过JNI访问的C ++对象图,其中某些根对象需要保持活动状态以保持孩子们的活力。根对象和子对象都在JVM域中具有镜像。但是,如果在C ++端(通过SWIG生成的终结器)收集和释放根对象,则子对象将变为无效,因为它们的C ++后备对象将被释放。

这可以通过确保根对象图的局部变量的生命周期超过上次使用子对象来解决。所以我需要一个惯用的功能,它不对物体做任何事情,但却不会被优化掉或移动(例如从一个循环中提升)。那是GC.KeepAlive(Object)在.NET中的作用。

Java中的近似等价物是什么?

PS:一些可能的说明性代码:

class Parent {
    long ptr;
    void finalize() { free(ptr); }
    Child getChild() { return new Child(expensive_operation(ptr)); }
}

class Child {
    long ptr;
    void doStuff() { do_stuff(ptr); }
}

// BAD CODE with potential for SIGSEGV
for (Parent p : getParents()) {
    p.getChild().doStuff();
}

麻烦的是,在doStuff执行时,GC释放Parent p将释放为Child分配的内存。已经观察到GC在实践中这样做。如果GC.KeepAlive可用,则可能会发生修复:

// BAD CODE with potential for SIGSEGV
for (Parent p : getParents()) {
    p.getChild().doStuff();
    GC.KeepAlive(p);
}

我可以,例如在p上调用toString,但我不会对其输出做任何事情。我可以暂时将p戳成阵列,但我怎么知道JVM不会丢弃商店?等

2 个答案:

答案 0 :(得分:2)

我猜你可以使用JMH Blackhole。它旨在确保在基准测试中不会消除参考,因此它应该可以工作。

基本上它只是将给定的对象引用与存储的volatile引用进行比较,并将后者重新分配一些小而且递减的概率(存储很昂贵,因此它被最小化)。

答案 1 :(得分:0)

每当垃圾回收器在调用本机方法时足够主动地声明该对象时,在Java世界中,几乎没有人会关心问题不存在或存在很多错误代码,其他SO answer似乎提供了使用GC.KeepAlive(Object)的合理替代方案,即使用非静态本机JNI方法,从而合理地防止了实例调用这些实例的任何可能的垃圾回收方法。