垃圾回收机制

内存分区

jdk1.8之前:堆中:新生区、老年区;方法区中:永久区

jdk1.8之后:堆中:新生区、老年区;内存中:元空间

GC垃圾回收,主要是在新生区和老年区。

详解

新生区、老年区

新生区分为:伊甸园区(Eden Space)、幸存区0区、幸存区1区。

  • 伊甸园区内存满时,触发一次轻GC,将GC后存活的对象存入幸存区0区和1区。
  • 幸存区0区和1区存满时,出发一次重GC,将GC后存活的对象存入老年区。

永久区(元空间)

用来存放JDK自身携带的Class对象。Interface元数据,存储的是Java运行的一些环境或类信息,这个区域不存在垃圾回收!只有关闭JVM虚拟机才会释放这个区域的内存。

  • jdk1.6之前:永久代,常量池在方法区中;
  • jdk1.7:永久代,但提出 “去永久代” 概念,将常量池放在堆中;
  • jdk1.8:无永久代,常量池在元空间;

将永久代改为元空间的原因,详见:JDK1.8之后的JVM内存模型

调优参数

-Xms:初始堆大小,默认1/64

-Xmx:最大堆大小,默认1/4

-XX:+PrintGCDetails :打印垃圾回收细节

-XX:+HeapDumpOnOutOfMemoryError :在内存溢出时生成Dump文件

常用GC算法

标记清除法

标记:对活着的对象进行标记。

清楚:对没有标记的对象进行清除。

优点: 不需要额外空间。

缺点: 两次扫描严重浪费时间,会产生内存碎片。

标记压缩法

对标记清除法的基础上添加了压缩步骤。

压缩:再次扫描,向一端移动存活的对象。

优、缺点同标记清除法,但不会产生内存碎片。

复制算法

将两个幸存区分为from和to。GC流程如下:

1.将Eden Space中存活的对象移到to区中;

2.将from中数据复制到to区;

3.清空from中数据;

4.将原from区设置为to区,原to区设置为from区。(一次GC完成)

5.当一个对象经历了15次GC,则转移至老年区。

优点: 没有内存碎片。

缺点: 浪费了一半幸存区的空间。

最佳使用场景: 对象存活度较低,因此用于轻GC。

引用计数法

为每个对象分配一个计数器,当对象被引用时计数加1,结束引用时计数减1,GC时清除所有引用计数为0的对象。

可达性分析算法

采用引用计数法来判断一个对象是否需要GC时,可能会出现循环引用的情况。例如:

MyObject object1 = new MyObject();
MyObject object2 = new MyObject();

object1.object = object2;
object2.object = object1;

object1 = null;
object2 = null;

此时,即使object1和object2为null,但计数器不为1,触发不了GC。

可发行分析则是通过一些“GC Roots”对象作为起点,将引用的对象向下链接,以此形成一条条的“引用链”。当进行GC时,会判断一个对象有没有可到达的“GC Root”,如果没有,则表明该对象没有引用,进行清除。

可达性分析算法.png

可作为“GC Roots”的对象包含以下几种:

  • 虚拟机栈中引用的对象:当程序正常创建一个对象时,对象会在堆中开辟一块空间,同时将这个空间的地址作为引用保存到虚拟机栈中。如果对象生命周期结束,则该引用会出栈,因此如果虚拟机栈中有引用,则说明该对象存活。大部分对象都以此为GC Root。
  • 方法区中静态属性引用或常量引用的对象:即使用了static、final关键字。
  • 本地方法栈中引用的对象:即使用了native关键字。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。