深入理解JVM之垃圾收集器和内存分配策略

  在前文深入理解JVM之内存区域中我们得知,Java堆是用于存放实例对象的,而且我们也知道了对象的创建过程中需要在Java堆中给新生对象分配内存空间。Java堆也被称为“GC堆”,因为在上面进行的垃圾回收非常频繁,所以在本文我们看看JVM的垃圾收集是怎么一回事,以及在Java堆中是如何进行内存分配的。可别忘了上文有提到的,垃圾收集器也会对方法区中的常量池进行回收,还有对类型进行卸载。

 可以试着带问题去看下文:

  • 如何判断对象是否死亡(两种方法)。

  • 简单的介绍一下强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)。

  • 垃圾收集有哪些算法,各自的特点?

  • HotSpot为什么要分为新生代和老年代?

  • 常见的垃圾回收器有那些?

  • 介绍一下CMS,G1收集器。

  • Minor Gc和Full GC 有什么不同呢?


本文结构:

  判断对象是否存活的方法

    引用计数算法

    可达性分析算法

  引用的类型

    强引用

    软引用

    弱引用

    虚引用

    虚引用

  对象死亡的“缓刑”过程

  回收方法区

  垃圾收集算法

    标记 —— 清除算法

    复制算法

    标记 —— 整理算法

    分代收集算法

  垃圾收集器

    Serial收集器

    ParNew收集器

    Parallel Scavenge收集器

    Serial Old收集器

    Parallel Old收集器

    CMS收集器

    G1收集器

  内存分配和回收策略


 判断对象是否存活的方法

  引用计数算法

    给对象中添加一个引用计数器,每当有一个地方引用它的时候,计数器值就加1;当引用失效时,计数器值就减一;任何时刻计数器为0的对象就是不可能再被使用的。但是这个算法在碰到类似于“如果我有一个阿拉丁神灯,那我最后的愿望是我还能许多三个愿望”的问题——对象之间相互循环引用的问题,那引用计数器就不会为0,无法通知GC收集器回收它们。

  可达性分析算法

    通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链的时候,则证明这个对象是不可达的。

    在Java语言中,可以作为GC Roots对象的包括下面几种:

      虚拟机栈中引用的对象

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

      方法区中常量引用的对象

      本地方法栈中JNI引用的对象


 引用的类型

  强引用——就是指在程序代码中普遍存在的,类似于一下代码。只要强引用还在,垃圾收集器即使报OutOfMemory错误也不会回收被引用的对象。

Object obj = new Object();
String a = "a";

  

  软引用——如果内存空间不够了才会将软引用描述的对象进行回收。这个特性很适合作为缓存。

       软引用可以和一个引用队列联合使用,如果软引用所描述的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。

       软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出等问题的产生。

       在JDK1.2之后,提供了SoftReference类来实现软引用。

import java.lang.ref.SoftReference;

public class Test {
    public static void main(String[] args) {
        SoftReference<Integer> sr = new SoftReference<Integer>(new Integer(1)); 
     System.out.println(sr.get());
     System.gc();
//进行垃圾回收
     System.out.println(sr.get());
  }
}

  输出结果:

1
1
View Code

  弱引用——当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用描述的对象。

       弱引用可以和一个引用队列联合使用,如果弱引用所引用的对象被JVM回收,这个弱引用就会被加入到与之关联的引用队列中。

       在JDK1.2之后,提供了WeakReference类来实现弱引用。

import java.lang.ref.WeakReference;

public class Test {
    public static void main(String[] args) {
        WeakReference<Integer> sr = new WeakReference<Integer>(new Integer(1));
        System.out.println(sr.get());
        System.gc();
        System.out.println(sr.get());
    }
}

  输出结果:

1
null
View Code

  

  虚引用——也称为幽灵引用或者幻影引用,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。

       为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。

       也可以用来跟踪对象被垃圾回收的活动。

       在JDK1.2之后,提供了PhantomReference类来实现虚引用,而且虚引用必须配合ReferenceQueue使用。

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class Test {
    public static void main(String[] args) {
        ReferenceQueue<Integer> rq = new ReferenceQueue<Integer>();
        PhantomReference<Integer> pr = new PhantomReference<Integer>(new Integer(1), rq);
        System.out.println(pr.get());
    }
}

  输出结果:

null
View Code

   

  虚引用与软引用和弱引用的区别:虚引用必须和引用队列(ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存前,把这个虚引用加入到与之关联的引用队列中。

参考:

https://www.jianshu.com/p/ec9464cc4b05

https://www.cnblogs.com/dolphin0520/p/3784171.html

猜你喜欢

转载自www.cnblogs.com/NYfor2018/p/9755034.html
今日推荐