我昨天读到了关于垃圾收集的内容,我不了解它的一些概念。我已经读过,对于小型收集,通常使用复制技术将可到达的对象移动到幸存者空间,对于主要的收集,它经常使用标记和扫描。
我不明白的第一件事是垃圾收集器从gc根开始并沿着图移动以检测实时实例,但它如何知道哪个对象是年轻的以及哪个对象是旧的?它如何知道哪个内存区域对象所在?
第二件事是,如果我们只进行次要的收集,那么gc如何知道年轻一代中的对象是不是被旧一代的对象引用,还是来自方法区域的静态引用?
最后一点是,在标记和扫描之后,有时会完成压缩。 gc如何知道哪些对移动对象的引用必须更新?如果我们有一个包含大量帧堆栈和千兆字节堆的线程的程序?它是否有一些内部结构以地图或其他形式提供该信息?
谢谢!
答案 0 :(得分:1)
答案取决于GC算法,因此您会发现答案有所不同。
GC如何知道哪个对象是年轻的以及哪个对象是旧的?它如何知道哪个内存区域对象所在?
对象的内存地址将回答每个区域往往固定在位置。可以调整大小,但这只会在JVM暂停所有工作线程时发生。还要记住G1收集器没有代数,所以答案确实因使用的算法而异。
gc如何知道年轻代中的对象是否未被旧代中的对象引用或者方法区域中的静态引用?
某些GC算法将对堆中的所有对象执行完整扫描。其他人依赖于观察到从旧到年轻的ref的数量相对较少,因此JVM跟踪它们并将它们用作标记目的的根。这种机制通常是记分卡系统,这就是为什么一些具有非常大的祖先空间的GC算法可以减慢年轻空间的GC的原因。因为每个对象的每个记分卡都必须进行检查,以确定它是否可以指向年轻一代。
最后一点是,在标记和扫描之后,有时会完成压缩。 gc如何知道哪些对移动对象的引用必须更新?
同样,答案确实有所不同,因为允许JVM改变这些细节。一些算法使用双间接,因此指针很容易定位和更新。这涉及为每个对象存储一个大索引。但是,当GC未运行时,已经证明这会降低用户代码的速度,因为正在运行的代码必须不断查找对象的实际位置,因此有些GC算法会跟踪引用。
Azul使用一种非常聪明的机制,它使内存页无效并存储在陷阱处理程序代码中访问的重定向映射。因此,它只需要存储已移动的对象的地址。而其他GC算法在扫描实时对象时跟踪信息。毕竟,我们不需要死者的信息。
答案 1 :(得分:1)
YoungGen / OldGen& PermGen是Java Heap所在的三个区域。 JVM非常精通每个界限。
收集垃圾时,GC首先决定运行哪个空间,然后确定该空间中每个对象的GC根。对象是年轻还是旧是由它所在的空间指定的。 GC维护每个对象的状态,就像每个对象存活了多少个GC周期一样,这使GC估计时间是否适合将对象从Young移动到Old。
对象图确定Old Gen引用是否引用了年轻的Gen对象。
如果压缩了Object,则Reference也会更新。当对象从Young移动时也会发生这种情况。 Old Gen。
答案 2 :(得分:0)