年轻一代集合中的活动对象是如何计算出来的?
据我了解,YGC 所花费的时间与 Eden 中存活对象的数量成正比。我还了解如何在主要集合中计算出活动对象(线程堆栈中的所有对象和静态对象以及可从这些对象传递到达的其他对象。)
但我不明白如何在年轻代集合中计算出活动对象? 如果它解析线程堆栈,那么它需要解析 eden + tenured space,我认为情况并非如此。那么JVM如何找到eden中的存活对象并将它们复制到To Survivor空间中呢?
I understand that time taken by YGC is proportional to number of live objects in Eden. I also understand that how the live objects are figured out in Major collections (All the objects in thread stacks and static objects and further objects reachable from those objects transitively.)
But I dont understand how the live objects are figured out in young generation collection ?
if it parses the thread stacks, then it need to parse eden + tenured space which is not the case I think. So how does JVM find the live objects in eden and copies them in To Survivor
space ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有关如何在 HotSpot 中实现分代收集的详细说明,请参阅本文。
一般来说,分代收集器按如下方式标记年轻代(假设我们只有两代):
在HotSpot中,包含年轻代引用的老年代对象是使用“卡表”来标识的。老年代被划分为512字节的区域,每个区域有一个“Card”。如果该区域包含任何旧的->新一代指针,在卡中设置了一个位。然后在新一代收集期间跟踪具有卡位设置的区域中的对象。
棘手的事情是在新的空间引用写入老一代对象时维护 Card 表。在 HotSpot 中,这是使用软件写屏障来实现的,只要将新的空间引用写入与卡相对应的内存区域,该软件写屏障就会设置适当的卡的脏位。正如链接的文章所指出的,这使得在对象中设置引用字段更加昂贵,但由于大多数时候只能收集新一代而节省了时间,所以这显然是值得的。
A good high-level description of how generational collection is implemented in HotSpot may be found in this article.
In general a generational collector marks the young generation as follows (assuming we just have two generations):
In HotSpot, old generation objects that contain young generation references are identified using the "Card Table". The old generation is divided into regions of 512 bytes, and each region has a "Card". If the region contains any old -> new generation pointers, a bit in the Card is set. Objects in regions with the Card bit set are then traced during a new generation collection.
The tricky thing is maintaining the Card table as new space references are written to old generation objects. In HotSpot, this is implemented using a software write-barrier that sets the appropriate Card's dirty bit whenever a new space reference is written into the memory region corresponding to the Card. As the linked article notes, this makes setting a reference field in an object more expensive, but it is apparently worth it due to the time saved by being able to collect only the new generation most of the time.
为了仅跟踪最年轻的一代,垃圾收集器扫描相同的根集(堆栈和寄存器),并且还扫描自上一次年轻代扫描以来已修改的所有较旧的(未收集的)代。只有那些已被修改的对象才可能指向年轻代对象,因为未修改的对象不可能指向上次修改后创建的对象。
所以棘手的部分是,GC 如何知道自上次 GC 以来哪些对象被修改了?有许多技术可以使用,但它们基本上都可以归结为跟踪对老一代对象的写入。这可以通过捕获写入(写入屏障)或仅跟踪所有写入目标(写入缓冲区、卡标记)来完成,所有这些都会在 GC 不运行时增加程序执行的开销(因此它不会显示为 GC 暂停时间,但确实显示在总运行时间中)。如果有的话,硬件支持会有很大帮助。跟踪不需要精确,只要扫描每个修改的老一代对象即可(扫描未修改的对象是浪费时间,但不会伤害任何东西)。
To trace just the youngest generation, the garbage collector scans the same root set (stacks and registers) and ALSO all the older (non-collected) generations that have been modified since the previous young generation scan. Only those objects that have been modified can possibly point at young generation objects, as unmodified objects cannot possibly point at objects that were created after their last modification.
So the tricky part is, how does the GC know which objects have been modified since the last GC? There are a number of techniques that can be used, but they basically come down to keeping track of writes to old generation objects. This can be done by trapping writes (write barriers) or just keeping track of all write targets (write buffers, card marking), all of which add overhead to the execution of the program while the GC is not running (so it doesn't show up as GC pause time, but does show up in the total elapsed time). Hardware support helps a lot, if its available. The tracking need not be exact, as long as every modified older generation object is scanned (scanning unmodified objects is a waste of time, but won't hurt anything).
我在这里引用 Brian Goetz 的文章中的相关文本。
I am quoting the relevant text from the article by Brian Goetz here.