Answers:
更新引用不是唯一需要暂停的操作。通常归类为“标记清除”的标准算法都假定整个对象图在被标记时保持不变。正确处理修改(创建新对象,更改引用)需要相当棘手的替代算法,例如三色算法。总称是“并发垃圾收集”。
但是,是的,压缩后更新引用也需要暂停。是的,使用间接寻址(例如,通过持久对象ID和到实际指针的哈希表)可以大大减少暂停。如果有需要,甚至可以使该部件无锁。与任何低级共享内存并发一样,正确的选择仍然很棘手,但是没有根本的理由认为它不起作用。
但是,这将具有严重的缺点。除了占用额外的空间(所有对象至少要有两个额外的单词)之外,它还会使每次取消引用的开销都大大增加。现在,甚至像获取属性一样简单的事情都涉及到完整的哈希表搜索。我估计性能影响会比增量跟踪更差。
计算机科学中的所有问题都可以通过另一种间接解决方案来解决……除了太多的间接设计问题
您的方法不能立即解决垃圾收集问题,而只能将其上移一个级别。而且要花多少钱!现在,每个内存访问都通过另一个指针取消引用。我们无法缓存结果位置,因为它可能已同时被重定位了,所以我们必须始终通过对象ID。在大多数系统中,这种间接方式是不可接受的,并且假设停止世界运行总成本较低。
我说你的主张只会解决问题,不会解决问题。问题在于对象ID的重用。现在,对象ID相当于我们的指针,并且只有有限数量的地址。可以想象到(尤其是在32位系统上),在程序的生命周期内,将创建多个INT_MAX对象,例如在类似以下的循环中
while (true) {
Object garbage = new Object();
}
如果仅增加每个对象的对象ID,则在某些时候我们将用完ID。因此,我们必须找出哪些ID仍在使用中,哪些ID是免费的,以便可以对其进行回收。听起来有点熟?我们现在回到了第一广场。
您的思路没有错误,您刚刚描述了与原始Java垃圾收集器的工作原理非常接近的内容
原始Java虚拟机[6]和某些Smalltalk虚拟机使用间接指针(在[6]中称为句柄)来引用对象。通过使用句柄,句柄允许在垃圾回收期间轻松地重定位对象,因为只有句柄直接指向每个对象:句柄中的一个。通过该对象间接引用该对象的所有其他引用。在这种基于句柄的存储系统中,尽管对象地址在对象的生存期内发生变化,因此无法用于哈希处理,但句柄地址保持不变。
在Sun当前对Java虚拟机的实现中,对类实例的引用是指向本身就是一对指针的句柄的指针:一个指向包含对象方法的表的指针,以及指向代表对象的Class对象的指针。对象的类型,另一个分配给从Java堆为对象数据分配的内存。
因此,它确实起作用,已经进行了尝试,其效率低下导致了世代标记和清除系统的发展。
Object.getHashCode()