Java引用及GC垃圾回收机制

Java引用

  1. StrongReference 强引用
  2. SoftReference 软引用
  3. WeakReference 弱引用
  4. PhantomReference 虚引用

1. StrongReference

介绍

我们平常用的最多的就是强引用了

Object obj = new Object();

这种形式的引用称为强引用

特点

  • 强引用所指向的对象在任何时候都不会被系统回收;
  • 由于特点1的原因,强引用可能导致内存泄漏。
    强引用只有引用置为null,垃圾回收器才会去回收该资源,否则不会去回收,即使在内存不足的情况下系统宁愿报oom(OutOfMemory)错误,也不会去回收强引用资源.

2. SoftReference

当JVM中的内存不足的时候,垃圾回收器会释放那些只被软引用所指向的对象。如果全部释放完这些对象之后,内存还不足,才会抛出OutOfMemory错误。软引用非常适合于创建缓存。

package com.nan.testproject;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

/**
 * -Xms256m
 * -Xmx2g
 */
public class ReferenceTest {
    public static void main(String[] args) {

        ReferenceQueue referenceQueue = new ReferenceQueue();
        // 软引用对象中指向了一个占用空间为1g的数据
        SoftReference<int[]> softReference =
                new SoftReference<>(new int[1024 * 1024 * 1024 / 4], referenceQueue);

        // 主动调用一次gc,由于jvm最大堆内存-Xmx设置为2g,此时JVM的内存够用,故softReference引用的对象未被回收
        System.gc();
        System.out.println(softReference.get());

        // 申请占用1g大小的数组,此时JVM内存不足,会导致一次自动的gc,会回收softReference对象中指向的数组对象
        int[] datas = new int[1024 * 1024 * 1024 / 4];
        SoftReference ref = null;
        // 当softReference中数组被回收后,会将引用放入绑定的referenceQueue中,referenceQueue.poll()也就不为null了
        while ((ref = (SoftReference) referenceQueue.poll()) != null) {
            // softReference中的int数组对象已被回收,此时可以置softReference该强引用为null
            // softReference = null;
        }
        System.out.println(softReference.get());
    }
}

输出

[I@75b84c92
null

注意,上面代码创建创建软引用部分,如果代码改为下面部分

int[] data = new int[1024 * 1024 * 1024 / 4];
SoftReference<int[]> softReference =
        new SoftReference<>(data, referenceQueue);

运行会报OOM,如下

[I@75b84c92
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.nan.testproject.ReferenceTest.main(ReferenceTest.java:26)

JVM进行软引用垃圾回收时只会回收被弱引用关联的对象,如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象。(弱引用和虚引用也是如此)

3. WeakReference

弱引用相比软引用拥有更短的生命周期,垃圾收集器一旦发现了只具有弱引用的对象,不管当前内存是否足够,都会回收它的内存。

/**
 * -Xms256m
 * -Xmx2g
 */
public class ReferenceTest {
    public static void main(String[] args) {
        WeakReference<byte[]> weakReference = new WeakReference<>(new byte[1024*1024]);
        System.out.println(weakReference.get());
        // 通知JVM回收资源
        System.gc();
        System.out.println(weakReference.get());
    }
}

JVM配置最大堆内存为2g,而代码中字节数组只占用1m内存,当JVM进行垃圾回收后,其就被回收了。

应用

  1. ApplicationPackageManager中图标缓存用到
  2. WeakHashMap

4. Phantom Reference

虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

要注意的是,虚引用必须和ReferenceQueue关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

/**
 * -Xms256m
 * -Xmx2g
 */
public class ReferenceTest {
    public static void main(String[] args) {
        ReferenceQueue referenceQueue = new ReferenceQueue();
        PhantomReference<byte[]> phantomReference = new PhantomReference<>(new byte[1024*1024],referenceQueue);
        System.out.println(phantomReference.get());
    }
}

运行结果输出null

ReferenceQueue

当gc(垃圾回收线程)准备回收一个对象时,如果发现它还仅有软引用(或弱引用,或虚引用)指向它,就会在回收该对象之前,把这个软引用(或弱引用,或虚引用)加入到与之关联的引用队列(ReferenceQueue)中。如果一个软引用(或弱引用,或虚引用)对象本身在引用队列中,就说明该引用对象所指向的对象被回收了。

当软引用(或弱引用,或虚引用)对象所指向的对象被回收了,那么这个引用对象本身就没有价值了,如果程序中存在大量的这类对象(注意,我们创建的软引用、弱引用、虚引用对象本身是个强引用,不会自动被gc回收),就会浪费内存。因此我们这就可以手动回收位于引用队列中的引用对象本身。

Java GC机制

1. 什么时候

GC具有不确定性,具体由JVM的回收机制决定,但内部不足时肯定会被调用,或者应用比较空闲时。我们无法手动指定其进行回收,也可以调用System.gc来提醒垃圾收集器进行收集,大多数会执行,但不保证会执行。主流Java虚拟机的垃圾收集器都采用分带收集算法(Generation Collection)。

  1. Minor Collection:新生代垃圾收集
  2. Full Collection:对老年代进行垃圾收集,收集频率较低,耗时长,速度一般会比Minor GC慢10倍以上。

Minor GC触发条件:

当Eden区满时,触发Minor GC。

Full GC触发条件:

  1. System.gc()方法的调用

此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI(Java远程方法调用)调用System.gc。

  1. 老年代空间不足

升到老年代的对象大于老年代剩余空间,会执行Full GC后空间仍然不足,则抛出如下错误: java.lang.OutOfMemoryError: Java heap space 为避免以上两种状况引起的FullGC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。

当然可以通过调优,用-XX:NewRatio控制新生代和老年代的占用空间比列,或者用-XX:MaxTenuringThreshold控制对象经历多少次Minor GC才晋升到老年代,默认为15。使得对象存储空间延迟达到Full GC,从而使得计时器引发gc时间延迟OOM的时间延迟,以延长对象生存期

2. 对什么东西

判断对象是否需要回收有两种垃圾标记算法:1. 引用计数算法,2. 根搜索算法

当对象引用计数为0,或者超出了作用域(但不包含超出作用域还被特殊强引用GC Roots持有),对象不可达时会进行标记,当进行GC时,会判断该对象是否重写了finilize方法,如果重写则回调用,但如果调用后还是不可达,那该对象在下次gc时会被回收。

3. 做了什么事情

删除不使用的对象,回收内存空间。对于Minor GC会采用复制清理算法(存活对象复制到To Survivor,回收Eden和from Survivor需要回收的对象,然后将To survivor和From Survivor空间位置互换)。对于Full GC采用的是标记-压缩算法(将回收对象清除后,把存活对象向左移动,使占用内存工整)
java GC是在什么时候,对什么东西,做了什么事情?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容