JVM内核—JVM垃圾回收

本课时承接上一篇JVM内核—JVM内存模型,将详细介绍JVM GC原理。如上节所示,JVM内存被划分为5个区域,栈区、JVM程序计数器空间由JVM执行引擎负责管理,本地方法栈由操作系统负责管理,因此需要垃圾回收的区域包括堆区和方法区(永久代区,JDK8以后为MetaSpace)。

目录:

  1. 内存泄漏
  2. 堆区Heap Space的GC
    1. GC过程
    2. GC算法
      1. 垃圾对象判定方法
        1. 引用记数法
        2. 根搜索法
      2. Java中的4种引用类型
        1. 强引用
        2. 软引用
        3. 弱引用
        4. 幻影引用
      3. 垃圾回收算法
        1. 标记清除算法
        2. 复制算法
        3. 标记整理算法
    3. 垃圾收集器
  3. 永久代区PermGen Space的GC

1.内存泄漏

package com.baidu;

public class MemoryLeakTest {
    public static void main(String[] args) throws InterruptedException {
       System.out.println(MemoryLeak.ml);//null
       MemoryLeak.ml = new MemoryLeak();
       System.out.println(MemoryLeak.ml);//com.baidu.MemoryLeak@15db9742
       MemoryLeak.ml=null;
       System.gc();//Memory leak occurs......会调用对象的finalize方法
       Thread.sleep(100);
       System.out.println(MemoryLeak.ml);//com.baidu.MemoryLeak@15db9742
    }
}

class MemoryLeak {
    public static MemoryLeak ml = null;
    
    @Override
    protected void finalize() throws Throwable {
       super.finalize();
       System.out.println("Memory leak occurs......");
       ml = this;
    }
}

2.堆区(Heap Space)的GC


2.1 GC过程

  1. 上图所示为堆区的内存结构,可以看到堆区由年轻代区(Young)和年老代区(Tenured)组成,年轻代区又包括Eden区和2个Survivor区(Survivor to和Survivor from)。
  2. 新new出来的对象一般存放在Eden区(当Eden区刚好满时,会直接存放于其中一个Survivor区)。
  3. 当Eden区满时,会进行一次Minor GC,回收掉Eden区98%以上的内存空间(因为新new出来的对象很多都是朝生夕死的)。
  4. 这时没有被回收的对象会被转移到其中的一块Survivor区(假设为Survivor from区),下一次Minor GC Eden区时,Eden区中仍然存活的对象会连同Survivor from区中的对象一起被转移到Survivor to区,并将由Survivor from区中转移过来的对象的age设置为1。(若Suivivor区满,则会直接复制到年老代区)。
  5. 下一次Minor GC时,重复第4步动作,以后这些没有被回收的对象在Survivor区中每熬过一次Minor GC,就将对象的年龄加1。(可以看到每一时刻总有一个Survivor区是空闲的,用来做复制容器,用到了复制算法,等会后面会讲到)。
  6. 当对象的年龄达到某个阈值(默认是15,可以通过参数-XX:MaxTenuringThreshold来设定),这些对象就会进入年老代区(对于一些较大的对象,则会直接进入年老代区)。
  7. 如果任意一个Survivor区满后,则会将其中的对象整个复制到年老代区。
  8. 当年老代区满后,触发Full GC,这时会同时对年轻代区,年老代区以及永久代区进行垃圾回收。

2.2 GC算法

2.1.1垃圾对象判定方法

2.1.1.1引用记数法

  • 定义:当一个对象被创建的时候,会为该对象生成一个引用计数器,每当有新的引用时,引用计数器的值+1,每当一个引用销毁时,计数器的值-1,当计数器的值归0时,则标志着该对象为垃圾对象。此种算法在JDK1.2之前的版本中被广泛使用。
  • 问题:当出现循环引用(即objA.obj=objB; objB.obj=objA),并且指向objA和objB的所有其他引用都销毁后,objA和objB还有一个相互的引用,引用计数器的值都为1,而实际上这两个对象都已经是垃圾对象了,但是由于引用计数永远无法归0,所以永远无法被回收。

2.1.1.2根搜索法

  • 定义:从离散数学中的图论引入,从初始节点(GC Root)开始寻找引用节点,形成引用链树,一直到叶子节点为止,当一个对象没有被引用链连接时,说明此对象不可达,即可判定为垃圾对象。
  • Java中可作为GC Root 的对象包括:

1、    虚拟机栈中引用的对象(本地变量表)

2、    方法区中静态属性引用的对象

3、    方法区中常量引用的对象

4、    本地方法栈中引用的对象(Native对象)


黄色为垃圾对象

2.1.2Java中的4种引用类型

2.1.2.1强引用

  • 定义:只要引用存在,就永远不会被回收。
  • 举例:
    package com.baidu;
    
    public class Referrence {
    	public static void main(String[] args) {
    		Object obj = new Object();
    		obj.equals(new Object());//obj对象对参数new Object()形成强引用,只有当obj这个引用被释放之后,new Object()对象才会被释放掉,这也是我们经常所用到的编码形式
    	}
    }

2.1.2.2软引用

  • 定义:内存溢出时强制回收。
  • 举例:
    package com.baidu;
    
    import java.lang.ref.SoftReference;
    
    public class Referrence {
    	public static void main(String[] args) {
    		Object obj = new Object();
    		SoftReference<Object> sf = new SoftReference<Object>(obj);//sf是obj的一个软引用。
    		obj = null;
    		System.gc();
    		System.out.println(sf.get());//输出java.lang.Object@15db9742,有时候会返回null(当且仅当内存溢出时)。
    	}
    }
  • 用途:软引用主要用来实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,提升速度;当内存不足时,自动删除这部分缓存数据。

2.1.2.3弱引用

  • 定义:一旦垃圾收集器运行并且扫描到只有该弱引用指向的对象时,就会毫不留情的删除。
  • 举例:
    package com.baidu;
    
    import java.lang.ref.WeakReference;
    
    public class Referrence {
    	public static void main(String[] args) {
    		Object obj = new Object();
    		WeakReference<Object> wf = new WeakReference<Object>(obj);//wf是obj的一个弱引用
    		obj = null;
    		//System.gc();若加上本句,则下面方法将输出null
    		System.out.println(wf.get());//java.lang.Object@15db9742
    	}
    }

2.1.2.4幻影引用

  • 本节暂时不作讨论。

2.1.3垃圾回收算法

2.1.3.1标记清除算法


  • 定义:从GC Root 开始扫描,标记存活的对象,标记完毕后再扫描整个空间,回收未被标记的对象。
  • 特点:不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但是会造成内存碎片。

2.1.3.2复制算法


  • 定义:首先将内存分为两块,利用根搜索算法把存活的对象紧凑的复制到另一块未被使用的内存,然后将前一块整块清空。
  • 特点:当存活的对象比较少时极为高效,并且不会存在内存碎片,但是需要一块空的内存交换空间。回收年轻代区通常使用此算法(Minor GC)。

2.1.3.3标记整理算法


  • 定义:采用标记清除算法一样的方式进行标记清除后,再将剩下的存活的对象往左端空闲空间紧凑排列。
  • 特点:提高了内存利用率,并且不会产生内存碎片,但是因为要做对象移动,所以成本较高。回收年老代区通常使用此算法(Full GC)。

2.3垃圾收集器

        JVM主要提供了三种垃圾收集器:
  • 串行收集器:使用一个垃圾收集线程,当垃圾收集线程工作时,会中断所有用户线程(Stop the World event)。
  • 并行收集器:使用多个垃圾收集线程,仍然会Stop the World。
  • 并行并发收集器:使用多个垃圾收集线程,并且用户线程与垃圾收集线程并行工作。
详情请见: 深入理解JVM

3.永久代区(PermGen Space)的GC

  1. 当永久代区被占满时,会触发Full GC,这时可能会导致class元数据信息被卸载。
  2. JDK8使用本地内存来存储类的元数据信息(Metaspace),也就是说方法区由本地内存所代替,JVM参数MaxMetaspaceSize用于限制所分配的本地内存的大小,若未制定,元数据空间会动态拓展。若使用量达到MaxMetaspaceSize所设定的值时,则触发GC。
结语:本节详细介绍了JVM GC 机制,下节将带领大家一起学习JVM GC 调优工具及常用参数设置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值