【问题标题】:How garbage collection determine time of garbage objects to collect and how long object is pushed from young generation to old generation?垃圾收集如何确定垃圾对象的收集时间以及对象从年轻代推送到老年代的时间?
【发布时间】:2018-12-03 16:09:26
【问题描述】:

为了针对这种情况进行优化,内存是分代管理的(内存池保存不同年龄的对象)。当代填满时,垃圾收集发生在每一代中。绝大多数对象都分配在专用于年轻对象(年轻一代)的池中,并且大多数对象都死在那里。 GC如何为不使用任何对象的对象定义时间到正在运行的程序中? GC如何决定将对象从年轻代移动到老年代?

【问题讨论】:

  • 首先,垃圾收集器通常在没有足够的可用内存来服务实际分配请求时运行。一些垃圾收集器还允许为正在使用的内存配置阈值,以触发收集。在任何一种情况下,触发任何事情的不是垃圾(未使用的对象)的数量,因为在垃圾收集器运行之前该数量是未知的。从年轻到老的提升通常是通过一个简单的计数器来实现的。在一个对象在可配置数量的集合中存活后,它会被提升到老年代。
  • 您好 Holger,我认为 GC 在后台运行并迭代对象以推送到老一代或年轻一代。如果对象不可达,内存池会跟踪并通知 GC,在复制内存期间 GC 未收集到时将删除对象。但是在将其移除之前,无法访问的对象保留了多长时间。例如:我们定义 10 纳秒,然后收集。但是如果 10 纳秒后,程序再次收集对象,对象变为可达,那么 GC 是如何解决这个问题的呢?
  • 你对垃圾回收有一个根本性的错误理解。首先,一个不可访问的对象永远不会再变得可访问,这就是不可访问的全部意义所在。应用程序无法访问它,因此,应用程序无法更改其状态。其次,垃圾收集确定哪些对象仍可访问(反之,哪些对象不可访问)的过程。没有人告诉垃圾收集器无法访问的对象,因为在垃圾收集器运行之前没有人知道。一旦确定,就没有理由保留无法访问的对象。
  • 谢谢霍尔格。我得到了它。非常感谢。
  • 您好 Holger,我阅读了 Mark and Sweep 算法,其中提到了 GC 检测不可达对象的方式以及回收堆空间以使空间再次可用的方式。如果我的应用程序因为 GC 运行而挂起,我们是否有任何解决方案可以在不重启 JVM 的情况下终止 GC?

标签: garbage-collection


【解决方案1】:

将年轻一代想象成一个堆栈。对象在当前堆栈指针处分配,指针移动已分配对象的大小(这真的很快)。

当指针到达 Eden 空间内存范围的顶部时,需要发生次要 GC。要跟踪所有活动对象,收集器将从创建根集开始。这是可从您的程序直接访问的所有对象的列表。收集器通过扫描寄存器和程序堆栈来寻找对象引用来做到这一点。这些对象中的每一个都将被标记为活动,然后扫描它们包含的对象引用以查找您在其中定义的变量。这会递归地发生,直到可以从您的代码中访问的所有对象都被标记。

一旦完成,Eden 空间中的所有活动对象都将复制到空的 (to) 幸存者空间。同样在这个时候,任何仍然存在于被占用(from)survivor空间的对象都会被复制到tosurvivor空间,除非它们已经达到tenuring阈值,在这种情况下它们被提升(复制)到老年代。

为了更具体地回答您的问题,由于上述算法,一个对象在年轻代中花费的时间将取决于几个因素。

  1. Eden 空间有多大(越大填满的时间越长)
  2. 您实例化新对象的速度有多快(您执行得越快,伊甸园空间填满的速度就越快)。
  3. 使用期限阈值。这是一个对象在被提升到老年代之前在幸存者空间之间复制的次数。
  4. 幸存者空间的大小也将发挥作用,因为如果这些空间被填满,对象将被更快地提升

老年代的收集可以使用几种不同算法中的一种,但确定哪些对象仍然存活使用与年轻代相同的方法,即创建一个根集,然后递归扫描所有对象引用。

【讨论】:

  • 非常感谢 Speakjava。
  • 作为 StackOverflow 礼仪的一个小要点,如果您对答案表示赞赏,可以单击答案旁边的向上箭头。
【解决方案2】:

我很难确切地知道您在这里寻找什么样的答案。但简短的回答是,当对象所在的分配空间变满时,对象会被移动。

年轻代分配空间通常相当小,并且通常会很快填满——大约每秒一次,具体取决于应用程序的类型。由于绝大多数对象的生命周期都非常短,因此运行时只需查找仍然可以访问的少数对象并将它们移动到幸存者空间。然后整个年轻代空间被清除干净并重新开始分配。

通常有两个幸存者空间,当一个空间已满时,其中的对象会移动到另一个空间。在移动了几次之后,对象会被移动到一个终身对象堆中,这通常由不同类型的 GC 算法(通常是某种标记清除过程)进行管理。

如果一个对象不能通过运行代码访问,它实际上就不再存在。不要将垃圾收集器视为搜索无法再访问的对象并将其删除——相反,正确的心理模型是垃圾收集器不断地保留 静止的对象死亡后可以到达。如果垃圾收集器停止关注某个对象,它就会自行消失:内存将被重新用于其他目的。

您可能会喜欢 Raymond Chen 以Everybody thinks about garbage collection the wrong wayWhen does an object become available for garbage collection? 开头的系列博文

【讨论】:

  • 您好 Daniel Pryden,感谢您的回答。我的问题与JVM有关。只需了解年轻一代中存在的未使用对象需要多长时间。在复制内存时,这些对象将死亡或移至旧生成。内存池保留对象多长时间并将其删除以恢复空闲内存?
  • “正确的心理模型是垃圾收集器不断地保持仍然可以访问的对象不死”。如果对象不被另一个对象使用,GC 将有一个算法使其无法访问。有多少次或多长时间的对象将被跟踪为不可访问?例如:我有两个对象 A 和 B,每个对象在内存中包含 10GB 数据,A 是静态的并且正在通过程序运行,而 B 正在运行到函数中。执行该功能后,B 将不再使用,A 仍在另一个模块上使用。 GC 如何保持 A 并将 B 标记为不可达对象。
  • 我认为你错过了我所说的重点。如果您无法通过任何代码路径读取的任何引用访问该对象,则它是不可访问的。 GC 不会使 事物无法访问,它们一旦无法再被访问,就会 无法访问。 GC 是分配器的“另一半”,因此它可以通过在同一个地方分配一个新对象来重用内存。所以它不需要找到所有不能再使用的对象,它只需要确保新对象不会被分配到仍然可以使用的对象之上。
  • 感谢 Daniel Pryden。
  • 嗨 Danial Pryden,当我的应用程序上的大对象因为重新运行问题而没有释放时,我看到 GC 正在运行并将日志写入服务器。那么 GC 运行来回收内存和 GC 运行在后台管理对象有什么区别呢?谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-04
  • 1970-01-01
  • 2010-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多