EdTe3:
结果是,终结器和常规方法可以在同一个实例上并发执行。这是一个如何发生的解释。代码本质上是:
class CleanResource {
int myIndex;
static ArrayList<ResourceImpl> all;
void doSomething() {
ResourceImpl impl = all.get(myIndex);
impl.doSomething();
}
protected void finalize() { ... }
}
给定此客户端代码:
CleanResource resource = new CleanResource(...);
resource.doSomething();
resource = null;
这可能会被抖动到类似于伪C的东西上。
register CleanResource* res = ...; call ctor etc..
// inline CleanResource.doSomething()
register int myIndex = res->MyIndex;
ResourceImpl* impl = all->get(myInddex);
impl->DoSomething();
// end of inline CleanResource.doSomething()
res = null;
像那样执行,
res
在内联后清除
CleanResource.doSomething()
已完成,因此在该方法完成执行之前不会发生GC。在同一实例上,不可能与另一个实例方法同时完成执行。
但是,写信给
物件
在该点之后不使用,并且考虑到没有围栏,可以在执行过程中提前移动,在写入之后立即移动:
register CleanResource* res = ...; call ctor etc..
// inline CleanResource->doSomething()
register int myIndex = res->MyIndex;
res = null; /// <-----
ResourceImpl* impl = all->get(myInddex);
impl.DoSomething();
// end of inline CleanResource.doSomething()
在标记的位置(<---),没有对CleanResource实例的引用,因此它符合收集条件,并且可以调用Finalizer方法。由于在清除最后一个引用之后的任何时候都可以调用终结器,因此终结器和
cleanresource.dosomething()。
并行执行。
edit2:keepalive()确保
this
在方法的末尾访问指针,这样编译器就无法优化指针的使用。并且该访问保证按指定的顺序进行(同步字标记了一个界限,该界限不允许在该点之前/之后重新排序读和写。)
原始职位:
这个例子是说,dosomething方法被调用,一旦调用,通过
这
指针可以提前读取(
myIndex
在示例中)。一旦读取引用的数据,
这
该方法不再需要指针,CPU/编译器可能会覆盖寄存器/将对象声明为不再可访问。因此,当对象的dosomething()方法运行时,GC可以同时调用终结器。
但自从
这
指针没有使用,很难看出这将如何产生任何实际效果。
编辑:好吧,也许如果有缓存指针指向通过缓存访问的对象字段,从
这
在它被回收之前,对象随后被回收,内存引用将变为无效。我有一部分人很难相信这是可能的,但再一次,这似乎是一个棘手的角落情况,我认为在JSR-133中没有任何东西可以阻止这种情况的默认发生。这是一个问题,一个对象是只被指向它的基的指针引用,还是被指向它的字段的指针引用。