在收集年轻代内存时,JVM收集器仅扫描属于年轻代的那些根对象(可从根集中直接访问的堆中的对象),并使用写屏障支持的卡表/记忆集来确定区域老一代可能包含对年轻一代中对象的引用的对象。
我的问题是,如果年轻的收藏家确定年轻一代中的某个特定对象只有一个来自旧一代对象的外部参考,它如何知道旧一代对象本身是不是垃圾,从而使年轻一代对象“活”并且没有资格收集?例如,可能有一条从根集直接到旧代的这个对象的路径,而后者又引用了上述年轻一代的对象。 年轻的收藏家通常会认为这个年轻一代的对象是现场的,还是在决定忽略/收集它之前如何确定指向它的老一代对象是否为实时/垃圾?
答案 0 :(得分:4)
如何知道旧代对象本身不是垃圾?
这并不是主要/完整系列的用途。假设旧的对象并不经常死亡。
当执行完整集合时,它会检查所有对象,但是当执行次要/年轻集合时,只清除年轻集合中的对象。
答案 1 :(得分:1)
问题是“如何进入这种情况?”
要创建从旧对象到年轻对象的引用,旧对象必须是可访问的,否则我们无法存储对其中的年轻对象的引用。为了在之后无法访问,我们必须至少修改一个根引用或之前引用相关旧对象的另一个旧对象。
正如您已经提到的,JVM会跟踪这些类型的写入,这是至关重要的,因为为了检测旧对象现在引用了一个年轻的对象,它必须知道旧对象的内存区域(aka卡)已被修改。原则上,由于卡片标记还意味着记住传入的引用,因此即使没有主要的gc,gc现在也能够检测到旧对象变得无法访问。它只需要考虑修改后的卡(或根集)来了解它。是否这样做取决于环境因素,例如所选择的gc算法,即您是使用CMS(不会)还是G1(可能),以及如何配置“混合集合”或实际内存压力。
当然,如果您使用并发收集器,则有可能在收集周期已经开始时进行将使旧对象无法访问的修改。在这种情况下,有可能在这个gc循环期间认为年轻对象是可达的,即使修改发生在一个纳秒之前也是如此。