.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不会丢弃商店?等