JAVA垃圾回收机制

一、概述

Java语言的特点就是将对象的管理权交给了内存管理机制,在jvm的自动内存管理机制下,不需要为每一个对象去写delete或者free代码,不容易出现内存泄漏或内存溢出的问题。但正因为java程序员将内存管理权力交给了内存管理机制,所以一旦出现内存泄漏或者内存溢出的问题,在对jvm内存结构不清楚的情况下,排查错误将会成为一项非常复杂且困难的工作。

二、运行时数据区

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。

2.1、程序计数器

线程私有;
可以看作是当前线程所执行的字节码的行号指示器;
程序计数器是唯一不发生任何OutOfMemoryError的区域。

2.2、Java虚拟机栈

线程私有;
每个方法被执行的时候,虚拟机会创建一个栈帧用于存储局部变量表、操作数栈、动态连接、方法出口等信息,每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程;
局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配的局部变量空间时完全确定的。

2.3、本地方法栈

与虚拟机栈所发挥的作用是非常相似的,其区别是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈是为虚拟机使用到的本地方法服务;
Java方法是由Java语言编写,编译字节码,存储在class文件中,与平台无关,本地方法是由其他语言(C++、汇编)编写,编译成和处理器相关的代码,保存在动态链接库中格式是各个平台专用的。

2.4、Java堆

线程共享;
此内存区域的唯一目的是存放对象实例;
Java堆是垃圾收集器管理的内存区域;
Java堆可以处理物理上不连续的内存空间,但在逻辑上它应该被视为连续的。

2.5、方法区

线程共享;
存储被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据;
运行时常量池是方法区的一部分。

三、判断对象已死

垃圾收集在回收前要做的第一件事就是判断对象哪些存活,哪些死去了。

3.1、引用计数算法

在对象中添加一个引用计数器,有一个地方引用它,计数器加一,当引用失效,计数器减一,计数器为零的对象就不可能再被使用;
原理简单,效率高;
难以解决对象之间相互循环引用的问题。

3.2、可达性分析算法

通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,隐居引用关系向下搜索,搜索过程所走过的路径称为“引用链”,如果某个对象到GC Roots间没有任何引用链相连,证明此对象不可能再被引用。
JAVA垃圾回收机制_第1张图片

3.3、引用

引用分为强引用、软引用、弱引用和虚引用;

  • 强引用,指程序代码中普遍存在的引用赋值,即类似“Object obj=new Object()”这种引用,只要强引用还存在,垃圾收集器就不会回收掉被引用的对象
  • 软引用,描述一些有用但非必须的对象,当内存不足时才会被回收
  • 弱引用,被弱引用的对象只能存活到下一次垃圾回收发生为止
  • 虚引用,为一个对象设置虚引用的目的只是为了能在这个对象被垃圾回收时收到系统通知

四、垃圾收集算法

4.1、标记-清除法

首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来;
执行效率不稳定,如果存在大部分需要被回收的对象,则必须进行大量的标记和清除;
第二个缺点是会导致内存空间碎片化

4.2、标记-复制法

将可用内存按容量划分为相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活的对象复制到另外一块上面,然后再把这块内存一次性清理掉;
算法只需要复制少量存活的对象,同时不用考虑内存碎片;
但是将可用内存缩小为原来的一半

4.3、标记-整理法

标记过程和标记-清除法一样,但不是之际金额对可回收对象进行清理,而是让所有存活的对象都想内存空间一段移动,然后直接清理掉边界以外的内存;
移动存活对象并更新所有引用这些对象的地方将会是一种极为负重的操作(Stop the world)

4.4、分代收集理论

  • 弱分代理论:绝大多数对象都是朝生夕灭的
  • 强分代理论:熬过越多次垃圾收集过程的对象就越难以消亡
  • 跨代引用假说:跨代引用相对于同代引用是少数,所以存在相互引用关系的两个对象是应该倾向于同时生存和同时消亡的

故此,收集器应该将Java堆划分出不同的区域,然后将回收对象依据年龄分配到不同的区域之中存储,也才能够针对不同的区域安排与里面存储对象存亡特征项匹配的垃圾收集算法。其中,Minor GC指目标为新生代的垃圾回收,Major GC指目标是老年代的垃圾收集,Full GC指整个Java堆和方法区的垃圾收集。

五、经典垃圾收集器

如果说收集算法是内存回收的方法论,那垃圾收集器就是内存回收的实践者。

5.1、Serial收集器

  • 这个收集器是一个单线程工作的收集器,“单线程”强调在他进行垃圾回收时,必须暂停其他所有工作线程
  • 它是HotSpot虚拟机运行在客户端模式下的默认新生代收集器,有着简单而高效的特点

5.2、ParNew收集器

  • Serial收集器的多线程并行版本
  • 是不少运行在服务端模式下的HotSpot虚拟机首选的新生代收集器
  • 除Serial收集器外,目前只有他能与CMS收集器配合工作

5.3、Paralledl Scavenge收集器

  • 新生代收集器,是能够并行收集的多线程收集器,基于“标记-复制”
  • 目标是达到一个可控制的吞吐量,所谓吞吐量就是处理器用于运行用户代码的时间与处理器总消耗时间的比值

5.4、Serial Old和Parallel Old

5.5、CMS收集器

运行过程,第一步为初始标记,STW,标记GC Roots能直接关联到的对象,速度很快;接着并发标记,从直接关联对象遍历整个对象图,耗时较长但不需要停顿用户线程;然后重新标记,STW,修正上一阶段用户线程导致标记变动的那一部分对象的记录;最后并发清除,清除已经死亡的对象,这个过程也是并发的。
CMS存在三个缺点,因为是并发执行清理线程和用户线程,所以对处理器资源敏感;无法处理浮动垃圾(在垃圾回收时产生的新的垃圾);基于标记-清除,会产生内存碎片。

5.6、G1收集器(略)

JAVA垃圾回收机制_第2张图片

你可能感兴趣的:(java,jvm)