垃圾回收会更改Java中的对象地址吗?

我读到垃圾回收在运行时会导致内存碎片问题。为了解决此问题,压缩由JVM完成,在JVM中,它接受所有活动对象并为其分配连续的内存。 这意味着对象地址必须不时更改吗?另外,如果发生这种情况,

  1. 是否也重新分配了对这些对象的引用?
  2. 这不会引起严重的性能问题吗? Java如何应对?
zj005386 回答:垃圾回收会更改Java中的对象地址吗?

  

我读到垃圾回收会在运行时导致内存碎片问题。

这不是垃圾收集堆的排他性问题。当您拥有一个手动管理的堆并以与前面的分配不同的顺序释放内存时,您可能还会得到一个零散的堆。能够具有与自动存储(即堆栈存储器)的后进先出顺序不同的生存期,这是使用堆内存的主要动机之一。

  

为解决此问题,压缩由JVM完成,在JVM中,它接受所有活动对象并为其分配连续的内存。

不一定是所有对象。典型的实现策略会将内存划分为逻辑区域,并且仅将对象从特定区域移动到另一个区域,而不是一次将所有现有对象移动。这些策略可能会考虑对象的年龄,例如代收集者将年轻一代的对象从伊甸园空间转移到幸存者空间,或者剩余对象的分布,例如“垃圾优先”收集器,这将顾名思义,首先将垃圾比率最高的片段撤出,这意味着获得空闲的连续内存块的工作最少。

  

这意味着对象地址必须不时更改吗?

当然可以。

  

如果发生这种情况,

     
      
  1. 是否也重新分配了对这些对象的引用?
  2.   

该规范没有规定如何实现对象引用。间接指针可以消除适应所有引用的需求,另请参见this Q&A。但是,对于使用直接指针的JVM,确实确实暗示着这些指针需要适应。

  
      
  1. 这不会引起严重的性能问题吗? Java如何应对?
  2.   

首先,我们必须考虑我们从中获得的收益。 “消除碎片”本身并不是目的。如果不这样做,则必须扫描可访问对象之间的间隙,并创建一个维护该信息的数据结构,然后将其称为“空闲内存”。我们还需要实现内存分配,以搜索此数据结构中的匹配块,或者在未找到完全匹配的情况下拆分块。与从连续的空闲内存块进行分配相比,这是一个相当昂贵的操作,在这种情况下,我们只需要按要求的大小将指针指向下一个空闲字节即可。

鉴于分配发生的频率要比垃圾收集高得多,垃圾收集仅在内存已满(或已超过阈值)时运行,这已经可以证明进行更昂贵的复制操作是合理的。这也意味着仅使用更大的堆就可以解决性能问题,因为它减少了所需的垃圾收集器运行次数,而幸存对象的数量将不会随着内存而扩展(无法访问的对象将保持不可访问状态,无论您推迟了多长时间。采集)。实际上,延迟收集会增加同时无法访问更多对象的机会。还要与this answer进行比较。

修改参考的成本不会比标记阶段遍历参考的成本高多少。实际上,非并发收集器甚至可以结合这两个步骤,在第一次遇到对象时转移对象,并改编随后遇到的引用,而不是标记对象。实际复制是更昂贵的方面,但是如上所述,不复制所有对象而是使用基于典型应用程序行为的某些策略(例如分代方法或“垃圾优先”策略)来减少所需的工作,从而减少了复制。 / p>

,

如果在内存中移动对象,其地址将更改。因此,指向它的引用将需要更新。当连续(在内存中)对象序列中的对象被删除时,就会发生内存碎片。这会在内存空间中产生一个 hole ,这通常是不好的,因为相邻的内存块具有更快的访问时间和更高的契机线拟合可能性,尤其是在其他情况下。应该注意的是,使用间接表可以防止参考更新达到所使用的最大间接级别。

垃圾收集具有适度的性能开销,不仅在Java中而且在其他语言(例如C#)中也是如此。正如Java如何解决这一问题,执行垃圾回收的策略以及如何最大程度地减少其对性能的影响取决于所使用的特定JVM,因为每个JVM都可以实现垃圾回收,但是这很令人满意。唯一的要求是它必须符合JVM规范。

但是,作为一名程序员,您应该遵循一些最佳实践,以充分利用垃圾收集并最大程度地降低其对应用程序的性能影响。请参见thisalso thisthisthis blog postthis other blog post。您可能要检查JVM specs,但它有点密集。

本文链接:https://www.f2er.com/3044406.html

大家都在问