java - 次要和主要 GC 周期
问题描述
AFAIK,Java GC 具有次要 GC(低成本)和主要 GC 周期(高成本)。如果对象在本地范围内,则在次要 GC 中对其进行清理。如果对象的引用存储在代码中的其他地方,那么它会在主要 GC 中被清除。
所以例如
void f() {
A a = new A();
a.doSomething();
}
根据我的描述(如果它当然是真的)对象 a 在次要 GC 中被清理。关于什么
void f() {
A a = new A();
B b = new B();
b.doSomething(a);
}
这里对象 a 作为参数传递给 B 的 doSomething 方法,也许 B 将引用存储在 B 本身中,但我们不知道。在这种情况下,对象a会在minor GC还是major GC中被清除?
解决方案
您需要一些关于 GC 工作原理的基本假设的帮助。
我们假设您将 HotSpot 与 G1 一起使用,因为还有其他几种以不同方式工作的替代方案(例如我为之工作的 Azul 的 Zing 中的 C4)。
堆分为两个区域,称为年轻代和老年代。首次分配对象时,从 Eden 空间提供空间,该空间是年轻一代的一部分(有时大对象直接在老一代中分配。但让我们像您的示例一样保持简单)。Eden 空间中的分配使用简单的指针碰撞方法,这会导致非常快速的分配。
当当前分配指针到达可用内存范围的末尾时,会发生次要 GC。这会将对象复制到幸存者空间之间的幸存者空间,并将寿命较长的对象提升到老一代。然后分配指针被重置到伊甸园空间的开头,有效地免费收集所有垃圾。
老一代。是一个单独的内存逻辑区域,使用不同的算法来回收空间和消除碎片。这是一个主要的收藏。
何时发生这些集合不是由分配对象的位置来确定的,而是由 VM 决定何时需要收集来确定的。这将取决于 Eden 空间何时耗尽或旧代中的可用空间何时耗尽。低于某个阈值。
在您的第一个示例中,不能保证在次要 GC 期间会收集对象“a”。如果 doSomething() 需要很长时间并且有其他线程分配大量对象,则可能会发生几次次要 GC,并且“a”最终可能会被提升为旧代。(并作为主要 GC 的一部分收集)。
在您的第二个示例中,如果 doSomething() 快速返回并且没有在任何地方记录对“b”的引用,则“a”和“b”都可以作为次要 GC 的一部分被收集。
推荐阅读
- typescript - 具有相同类型的所有成员的类类型
- video - FFMPEG:合并图像和音频以创建视频
- apache-kafka - 生产者的基准测试 - apache kafka
- powershell - 打开 CMD 时如何提示/隐藏密码?
- java - “字段需要一个无法找到的 bean。” Spring找不到我的存储库接口
- regex - 如何在不添加转义字符的情况下让 python 子进程运行正则表达式模式?
- docker - 如何使用 docker-machine 和 openstack 附加卷
- php - 属性 [] 不存在于属于多个枢轴关系
- angularjs - AngularJS - 带有复选框的 Spring POST 请求
- r - 根据特定列用其他值填充数据框列