GC--垃圾回收机制

参考 https://www.cnblogs.com/daemonox/p/4419579.html

内存区域

内存构成.png
  1. 程序计数器

1.1. 程序计数器是一块较小的内存空间,它是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变该计数器的值来选择下一条需要执行的字节码指令,分支、跳转、循环等基础功能都要依赖它来实现。每条线程都有一个独立的程序计数器,各线程间的计数器互不影响,因此该区域是线程私有的。

1.2. 线程在执行一个Java方法时,该计数器记录的是正在执行的虚拟机字节码指令的地址,当线程在执行的是Native方法(调用本地操作系统方法)时,该计数器的值为空。另外,该内存区域是唯一一个在Java虚拟机规范中么有规定任何OOM(内存溢出:OutOfMemoryError)情况的区域。

  1. Java虚拟机栈

java虚拟机栈也是线程私有,与线程的生命周期一致,在执行每个方法都会创建一个Stack Frame。每一个方法从开始执行到结束,对应一个Stack Frame在虚拟机值栈中从入栈和出栈的过程。如果线程请求的栈深度大于虚拟机所允许的深度,就会出现StackOverFlowException。如果允许动态扩展,在扩展的过程中,如果无法申请到足够的内存,则会抛出OutOfMemoryException异常。

  1. 本地方法栈
    和java虚拟机栈的作用类似,不同点在本地方法栈主要是为虚拟机使用到的Native方法提供服务,本地方法栈也会抛出StackOverFlowException和OutOfMemoryException异常。

  2. java堆
    堆是java虚拟机中内存中最大的一块,被所有线程共享的一块内存区域,在虚拟机创建时创建。作用就是存放对象实例,所有的对象的实例都需要在这里分配内存。几乎所有的对象实例和对象数组都需要在堆上分配。是java虚拟机内存回收的管理的重要区域,因此也被称为“GC”堆,可以被分为:新生代和老年代;Eden空间、From Survivor空间、To Survivor空间。如果堆中没有内存完成实例分配,并且堆也无法扩展时,则抛出OutOfMemoryException异常

  3. 方法区
    方法区和java堆一样,是各个线程共享的内存区域,用于存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译的代码等数据。通常被开发人员成为“永久带”。这个区域的内存回收的目标就是针对常亮池的回收和对类型的卸载,也是较为难处理的部分。

GC机制的基本算法:分代收集

其他算法参见https://blog.csdn.net/xzm_rainbow/article/details/84997446

一般情况下,新建的对象都会放在Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC,如果还存活,就会放到survivor区,对象在survivor区熬过一次Minor GC,年龄就会增长一岁。当他们的年龄到达一定程度,就会被移到老年代中。

一、年轻代

分为3个部分:Eden、survivor(from)、survivor(to)。比例为8 :1 :1

因为年轻代中的对象基本都是朝生暮死(80%以上),所以年轻代用的垃圾回收算法是复制算法。基本思想是把内存分为2块,每次用一块,进行一次GC后,把活着的对象复制到另一块上,把当前块清空。

1.初始状态:对象只存在于Eden和survivor(from)区域,survivor(to)为空。

2.GC开始,Eden中所有存活的对象移动到To区,From区根据年龄决定去向。年龄阈值根据-XX:MaxTenuringThresholdl来决定。此时没有达到阈值的对象会被复制到To区,达到阈值的对象就会被移动到老年代中。

3.GC结束后,Eden区和From区已经被清空。

4.然后from区和to区会交换身份。To区变为From区,from区变为To区。这是为了保证To区一直为空。

5.重复Minor GC,直到To区被填满,填满后会将所有对象移动到老年代中。

年轻代中的参数:

1.-XX:NewSize和-XX:MaxNewSize

设置年轻代的大小,建议设为堆的1/3或者1/4,两个值设为一样大。

2.-XX:SurvivorRatio

设置Eden和一个Survivor的比值。

3.-XX:PrintTenuringDistribution

这个参数用于显示每次Minor GC时Survivor区中各个年龄段的对象的大小。

4.-XX:InitialtenuringThreshol和MaxTenuringThreshol

用于设置晋升到老年代的对象年龄的最小值和最大值

二、老年代

老年代一般占堆的2/3空间,它放置的都是生命周期较长的对象,或者是年轻代无法放置的体积较大的对象。

老年代的垃圾回收算法是标记压缩算法:标记存活的对象,让这些对象向一端移动,保证内存的连续。

1.标记垃圾对象(黄色)

2.清除垃圾对象

3.内存碎片整理

三、持久代(方法区)

存放静态文件,如java类、方法等。持久代对垃圾回收没有显著影响。

你可能感兴趣的:(GC--垃圾回收机制)