0%

​ 主要记录一下,堆内存的结构,以及垃圾回收。

​ 堆由于存放的是对象实例,对象主要是存放数据,所以当一个对象没有使用、或者没有引用指向它时,它就有可能会被垃圾回收器回收。

​ 在jdk1.8之后,堆区主要有三个区域,新生代、老年代、元空间。

​ 新生代包括Eden区(伊甸园区)、 survivor0区(from区)、survivor1区(to区)。

gc

ps: 元空间在jdk1.7之前叫做永久代,元空间中主要存放的是java自带的类信息,如rt.jar包下的类,常用的集合框架等等…

​ 因此,垃圾回收主要发生在前面两个区域。首先要说明的有两点:

  1. 对于大部分对象,当它被创建并且在堆中分配内存时,这个对象都是在伊甸园区(后面都说新生代);
  2. 对于大对象会直接进入老年代。像字符串、数组等。这样是为了防止对象复制而降低效率。
gc

大部分的对象使用完毕之后就会被回收,因此在新生代发生gc是十分频繁的。当新生代满了之后,就会发生一次young gc,一次ygc过后,存活下来的对象会被复制进入from区,当新生代发生第二次ygc后,所有存活下来的对象将会被复制到to区,此时,from区会清空,而from区和to区会角色互换。即两者的名字会交换。就是要保证to区是空的。当进入一次幸存者区时,这些对象的年龄就会+1,而当一个对象的年龄达到15岁时,就会进入老年代。

​ 老年代发生gc的次数不像新生代那么频繁。 这是因为老年代的空间大小是新生代的2倍,所以速度也会慢8-10倍。

gc算法

​ 目前jvm采用的是分代收集算法,根据不同的区域,来使用合适的算法。

​ 复制算法: 新生代使用的算法,所以有from和to两块大小完全一样的空间,使用这种算法是因为在新生代,一次gc可能有90%的对象会被回收。并且不会产生内存碎片,但是会需要两块空间,所以相对来说耗内存。

​ 标记清除算法: 老年代使用,先对需要回收的对象进行标记,然后在进行删除,因为老年代中的对象大部分都不会被回收,所以使用复制算法显然行不通,但是这种算法,需要对内存区域进行两次扫描,所以效率会比较低,并且会产生内存碎片。

标记整理: 和标记清除一样,先标记要回收的对象,然后将存活对象往一端移动,然后清除边界外的内存。

判断对象死亡

​ 可以采用引用计数法来判断对象死亡,给对象添加一个计数器,当有一个引用指向这个对象的时候,就+1,当引用失效时,就-1,当计数器为0时,说明没有任何引用指向该对象。则宣告对象死亡。需要被jvm回收。

-------------本文结束感谢您的阅读-------------