JVM内存管理—内存回收—哪些内存需要回收?

哪些区域需要回收

运行时内存分为5个区域:程序计数器、虚拟机栈、本地方法栈、堆、方法区,这些区域是如何回收的?

1-程序计数器、虚拟机栈、本地方法栈

这3个区域是随着线程而生,随着线程而灭,栈中的栈帧数据随着方法的调用到结束有条不紊的进行着入栈出栈,每一个栈帧中分配多少内部基本上在类结构确定下来(类加载)就已知了。内存分配和回收具有确定性,随着方法的结束或者线程的结束后,内存自然就会被回收了。

2- java堆和方法区

一个接口中的多个实现类需要的内存可能不一样,一个方法的多个分支需要的内存也不一样,我们只有在程序处于执行期间才能知道会创建哪些对象,对这部分的内存分配和回收是动态的,垃圾回收主要关注的是这部分的内存

判断对象是“生”是“死”?

引用计数算法

java虚拟机没有采用引用计数算法来判断对象是否生存,主要考虑的是它很难解决对象之间的相互循环引用的问题。

可达性分析算法(Reachablity Analysis)

基本思路是:从每一个GC Roots出发找到它所有可达的对象,走过的路径成为引用链,被引用链串起来的就是存活对象;其他的虽然存在引用关系,但是GC Roots不可达的,判定为可回收对象。、
GC Roots :可作为的对象包含以下几种:

  1. 虚拟机栈(栈帧中本地变量表)中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区常量引用的对象
  4. 本地方法栈中JNI(Native Method)引用的对象

引用与缓存

为了更细致的管理对象的内存,对象引用进行了扩展,分为:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference,也叫幽灵引用)

强引用
  • Object obj = new Object(); 这种通过关键字new出来的对象就属于强引用,普遍存在的,只要这种引用还关联着对象,就不会被垃圾回收器回收。
  • **内存空间不够时,不会进行垃圾回收,而是直接抛出内存溢出异常 **
软引用

用来描述有用但是并不必需的对象,在系统将要发生内存溢出异常之前,JVM将会把这些对象标记成垃圾数据,并对这些标记的数据进行二次回收,若回收后还是没有足够的内存分配,才会抛出内存溢出的异常。 用法: 用来实现内存敏感的缓存

import java.lang.ref.SoftReference;
class ReferenceTest{
    Object obj = new Object();//强引用
    SoftReference<Object> sr = new SoftReference<Object>(obj);//关联软引用
    // 取消强引用,只保留软引用
    obj=null;
    pass(...);
    //通用的处理,以及softreference的复用模式
    if(sr.get() != null){
        Obeject getRef = sr.get();
        use(getRef);
    }else{
        Object newObj = new Object();
        sr = new SoftReference(newObj);//重建软引用
    }
}
  • 注意
    1.在虚拟机内存空间足够大的时候是不会发生内存回收的,而且GC的优先级最低,只有所有线程都停止时才有可能执行GC(即使使用System.gc()也只是告诉JVM这是一个执行GC的好时机,但是实际上JVM会自己决断是否达到了这个条件,比如没有线程正在执行,这是GC这个守护线程就会执行),因为GC有一定的代价。所以与软引用关联的对象在内存充足时是不会发生的,只有处于内存溢出的边缘才会发生回收操作。
    2.虽然与软引用关联的对象可能会被收回,但保存这个软引用关系的SoftReference变量并不一定会被回收,所以出现了ReferenceQueue来管理这些变量。
弱引用
  • 弱引用描述的是非必需的对象:被弱引用关联的对象只能生存到下一次GC回收发生之前,当GC工作时,无论当前空间是否足够,都会回收只被弱引用关联的对象
  • 用法:一般会和ReferenceQueue进行关联
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
public class WeakReferenceTest{
    public static void main(Stting[] args) throws Exception{
        Object obj = new Object();
        //ReferenceQueue的作用:
        //当弱引用关联的对象被标记为垃圾,准备回收时,
        //会自动把保存弱引用的对象WeakReference放到ReferenceQueue中,等待被处理
        //主要目的是:引用关联的对象被回收了,但存储引用的对象没有及时回收会造成
        //内存膨胀
        ReferenceQueue<Object> rf = new ReferenceQueue<Object>();
        WeakReference<Object> wf = new WeakReference<Object>(obj,rf);
        WeakReference<Object> wf_q = null;
                // poll方法,删除队尾引用并返回
        while(wf_q = rf.poll()!= null){
            // do something for remove reference
        }
    }
}
虚引用
  • 最弱的一种引用关系,无法通过虚引用来获取对象的实例
  • 用途:仅仅是在这个对象被回收时收到一个系统的通知。
总结

对于软引用和弱引用,被GC标记为垃圾准备回收时会清除对应的引用,即get方法返回null,然后放入绑定的引用队列中,理论上此时没有真正被回收,只是没有办法在访问到;但是对于虚引用则是在发生回收时放入队列,也是唯一一种确认对象被回收而加入队列的引用,可以利用这一特性做一些有趣的事。


finalize()越狱

通过一条到墙外的地下通道(finalize)、一列快速列车(F-Queue)的惊险越狱大片

  • 可达性分析发现这个对象没有到GC Roots的引用链(快到砍头的时候了),进行第一次标记如果对象没有覆盖Object的finalize方法,或者已经执行过了一次finalize方法,则这个对象的finalize不会执行,等待下一次GC被回收(蠢蛋和倒霉蛋的组合,一个不知道这个秘密通道,一个越狱失败被抓了回来成为重点照顾对象,没日没夜的毒打,只能等死了)
  • 如果覆盖了finalize方法但还没有执行(已经踩好点了,还在做最后的精密计划,天一黑,就行动),将这个对象放到F-Queue中等待执行finalize方法(通过地下秘密通道到达狱外,此时列车也到了,正在排队刷卡上车...)
  • 以低优先级执行F-Queue中对象的finalize方法,进行第二次标记,如果finalize中将自己对象的引用与外面的引用链上的对象建立了链接,则将其移出F-Queue,成功逃脱回收(滴,学生卡,上车落座,系好安全带,老司机要飙车了),如果没有建立与引用链的链接,则等待下一次GC被回收(滴,余额不足,请及时充值,司机说穷鬼,没钱还想做快速列车。哎哎哎~,老司机带带我呀,带带我呀,带我呀,我呀,呀...曾经的秋名山车神遗弃在角落。)

进行了两次标记:第一次标记是筛选有哪些finalize方法是需要执行的;第二次标记是哪些finalize方法关联了引用链,将其移出队列。

public class SaveSelfTest {
    public static Scofield BreakAway= null;//逃生专列
    public static void main(String[] args) throws Exception{
        Scofield michael = new Scofield();
        michael.sayHi();
        
        //第一次逃脱,成功
        michael = null;//置为null,触发回收的条件
        System.gc();
        Thread.sleep(200);
        
        if(BreakAway != null){
            BreakAway.sayHi();
        }else{
            util.print("ScoField:Please save me,I'll dead next morning!");
        }
        
        //第二次逃脱,失败,finalize函数只能最多被执行一次
        BreakAway = null;
        System.gc();
        Thread.sleep(200);
        
        if(BreakAway != null){
            BreakAway.sayHi();
        }else{
            util.print("ScoField:Please save me,I'll dead next morning!");
        }
        
        System.exit(0);
    }

}
class Scofield{
    public void sayHi(){
        util.print("Hi, I'm Michael ScoField!");
    }
    @Override
    protected void  finalize() throws Throwable{
        super.finalize();//Object
        util.print("Scofield gets on car!");
        SaveSelfTest.BreakAway = this;//关联引用链
    }
}
class util{
    public static void print(String str){
        System.out.println(str);
    }
}
/* Output
Hi, I'm Michael ScoField!
Scofield gets on car!
Hi, I'm Michael ScoField!
ScoField:Please save me,I'll dead next morning!
*/

参考链接
http://www.cnblogs.com/jiangyi-uestc/p/5679331.html
http://www.importnew.com/14115.html

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

推荐阅读更多精彩内容