您能否回答一下有关JVM垃圾收集过程的问题?
为什么堆分为Eden,Survivor空间和Old Generation?
当处理年轻的疏散时,通过从根开始的引用访问对象以找出无法访问的对象。可到达的对象被标记为“活着”,并且未被标记并且将被删除。
因此,会考虑所有对象,包括在旧代中分配的对象,如果可以访问,也会被访问并标记。
据我所知,同时回收年轻一代和老一代的要求很高,因为这些世代位于记忆的不同连续部分。
但是,为什么我们需要这种划分,即使在Young疏散级别上最简单的标记之后,如果所有可到达和无法到达的对象都已知并且可以删除,那么我们将整个位图包含所有活动和死对象?
我也知道弱代的假设,但为什么我们需要分裂呢?
答案 0 :(得分:2)
基本前提是,当创建新对象时,不存在从旧对象到新对象的引用,对于许多对象,甚至大多数对象,它永远不会改变。这意味着,如果您可以证明仍然没有从旧对象到新对象的引用,或者您确切知道已经创建了哪些引用,那么您可以执行仅对年轻代进行扫描的“次要”垃圾回收。
这意味着必须跟踪和记住对旧对象的引用更改(但回想一下这种更改不会经常发生的前提)。
一种实施策略是Card Marking:
如果垃圾收集器没有收集整个堆(增量集合),垃圾收集器需要知道从堆的未收集部分到堆的一部分的指针。正在收集。这通常用于分代垃圾收集器,其中堆的未收集部分通常是旧代,并且堆的收集部分是年轻代。用于保存此信息的数据结构(旧代指向年轻代对象的指针)是记住的集合。 卡表是一种特殊类型的记忆集。 Java HotSpot VM使用字节数组作为卡表。每个字节称为卡。卡对应于堆中的一系列地址。 Dirtying a card 意味着将字节值更改为脏值;一个脏值可能包含一个新的指针,从旧一代到卡所覆盖的地址范围内的年轻一代。
处理卡意味着查看卡片以查看是否存在旧代到年轻代指针,并且可能使用该信息执行某些操作,例如将其传输到其他数据结构。
当然,如果使用代数只能让我们在扫描期间跳过某些内存区域,并且维护这些记忆集不会超过节省,那么使用代数只会提供一个好处。