Java 垃圾回收机制 - 标记清除算法和分代假设 Java 垃圾回收机制是 Java 语言中的一种自动内存管理机制,旨在释放无用对象所占用的内存空间,以避免内存溢出和提高系统性能。其中,标记清除算法是 Java 垃圾回收机制中的一种主要理论算法。在实践过程中,为了满足真实情景需要,需要进行许多调整,从而导致内存碎片化和磁盘碎片化。 标记清除算法的主要思想是,首先标记所有可达对象,然后清除不可达对象。标记过程中,JVM 需要确保区域被不可达对象填充。这会导致内存碎片化,同样会导致磁盘碎片化,从而产生两个问题:写操作因为寻找下一个足够尺寸的空间变得耗费时间,这个写操作不再简单。当创建新对象的时候,JVM 分配一个连续的空间。如果内存碎片遍布每一个点,没有足够的空间容纳新创建的对象,分配就会发生错误。 为了避免上述问题,JVM 会确保碎片化不会失控。因此不会仅仅标记清除,垃圾回收期间,“内存整理”进程同时在工作。这个进程重新分配所有的可达对象,让他们紧密排列,消除(或者减少)碎片。 在 Java 垃圾回收机制中,还有一个重要概念,即分代假设。根据分代假设,对象可以分为两种:绝大多数对象很快就成为无用对象,很少部分对象讲过很长时间存活下来。基于这个假设,VM 内存空间被划分为 Young 代和 Old 代,后者有时也叫做 Tenured。这种方式虽说不上毫无问题,但可以大大提高垃圾回收的性能。 在 Young 代中,垃圾回收器收集一个分代中的对象的时候,不同分代中的对象彼此相互引用的时,实际上被当作“GC roots”。为了提高垃圾回收的性能,Java 垃圾回收机制还提供了一些其他机制,如 Eden 区、Survivor 区和 Old 区等。 Eden 区是对象被新创建的时候分配的内存区域。在这个区域中,多线程可以同时创建多个对象。在 Eden 区里,Eden 被分成一个或多个 Thread Local Allocation Buffer(缩写:TLAB)。在这些缓存里,JVM 允许线程在对应的缓存中分配绝大多数的对象,避免昂贵的多线程同步。 Survivor 区紧邻 Eden 区的下一个区域时两个叫做 from 和 to 的 Survivor 区。需要注意的一点,两块区域中的一块是空的。Survivor 中的空的区域会保存下一刻 Young 代中垃圾回收后的对象。Young 代所有存活的对象(包括 Eden 区和 Survivor 区中非空的 from 区域)被复制到 Survivor 区的“to”区域。在这之后,“to”区域存放所有对象,“from”区域清空。两者进行调换(译者注:即 from 变成 to,to 变成 from)。 在两个区域进行数次复制存活对象操作,直到一些对象足够成熟(“old enough”)。记住这一点,基于分代假设,一些对象在数次 GC 之后存活下来,而且在很长一段时间内继续被引用。这样的“tenured”对象会升级到 Old 代。这种情况发生的时候,对象不再从 Survivor 区一个区域移动到另外一个区域,而是进入 Old 区,在成为不可达对象之前它们一直存在在 Old 区中。 为了确定哪些对象“old enough”,需要为 Old 区提供一种算法,GC 记录幸存对象的详细信息。每代 GC 完成之后,那些依然存活的对象年龄进行增长。每当年龄超过设定的阀值之后,对象才会被升迁到 Old 区。实际上阀值被 JVM 动态设定,XX:+MaxTenuringThreshold 除外,它设置最高限定。XX:+MaxTenuringThreshold=0 表示跳过 Survivor 区的两个区域之间复制过程直接进入 Old 区。JVM 默认阀值是 GC 循环。
- 粉丝: 34
- 资源: 325
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
评论0