Java虚拟机之内存管理

内存模型
一说到内存管理,首先需要了解它的内存模型。
虚拟机的内存模型在jdk1.8之后有了一些变化,我们分开来看,请看下图:


由图我们可以看出,jdk每个版本都会有新生代和老年代,唯一不同的是小于1.8的版本为永久代,而大于等于1.8的版本去掉了永久代,转为元空间(Meta Space)。
永久代也就是存储的数据区里面的方法区,如果程序在运行中发生PermSpace溢出,则说明永久代内存不够,需要调整JVM参数增加永久代内存空间。
jdk1.8以后出现了MetaSpace,它和永久代不同的是,它的内存空间是动态扩展的,当然我们也可以设置MaxMetadaSpace来设置最大元空间内存数量,也就是在1.8以后设置PermSize是无效的。
本文主要讲解jdk1.8以前得内存管理机制
垃圾回收机制
在现代编程语言中,对垃圾回收算法主要有两种方式:引用计数器和可达性分析。
引用计数器
引用计数的原理大致是这样的:为每一个创建的对象设置一个引用计数,每当对象被引用一次后,引用计数加1,当对象引用失效时,引用计数减1,当引用计数为0是说明没有任何对象引用了,即可释放该对象。
引用计数的一个弊端是,他无法解决对象间相互引用的问题,比如下面这段代码:

public class RefrenceCountingGC {

    private Object instance = null;

    public static void main(String[] args) {
        RefrenceCountingGC gc1 = new RefrenceCountingGC();
        RefrenceCountingGC gc2 = new RefrenceCountingGC();
        gc1.instance = gc2;
        gc2.instance = gc1;

        gc1 = null;
        gc2 = null;
        //假设采用引用计数算法,在这里发生GC,gc1和gc2能否被回收?
        System.gc();
    }
}

两个对象始终处于相互引用阶段,因为引用计数永远无法为0,因此就不能自动释放它。
可达性分析
为了解决引用计数出现的这些问题,可达性分析算法出现了。
在主流的编程语言中,java和c#都是通过可达性分析来判定对象是否存活的。
它的原理大致是:通过一系列的被称为“GC Roots”的对象作为起始点,然后从这些节点开始向下搜索,搜索的路径连成的一条线,我们称之为“引用链”,当前一个对象到GC Roots没有任何引用链,即我们说的这个对象不可达时,则说明该对象是可以被回收的,通过下图可以更好的理解:



当一个对象不可达时,并不能代码这个对象就能马上被回收,他会处于死缓状态,而一个对象真正要回收时,至少需要经历两次标记。第一次标记的前提条件是,看该对象是否覆盖了finalize()方法或者finalize()方法被虚拟机调用过,如果覆盖了finalize()方法并且虚拟机还没有调用过,这时会标记它,该对象还有机会存活,方法很多,比如在finalize()方法内存引用该对象。
如果进行第二次回收时,由于虚拟机已经调用过finalize()方法,就不会再调用他了,这时该对象就会真正宣告死亡了。
请看下面这段代码:

public class GCRoot {

    private static GCRoot instance = null;

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalized执行");
        instance = this;
    }

    public static void main(String[] args) throws Exception{
        instance = new GCRoot();
        instance = null;
        System.gc();
        //因为finalize执行优先级较低,这里等待0.5秒
        Thread.sleep(500);
        if(null != instance){
            System.out.println("对象拯救成功!");
        }else{
            System.out.println("对象被释放!");
        }

        //和上面的代码一样,不会执行finalize方法,所以拯救失败
        instance = null;
        System.gc();
        if(null != instance){
            System.out.println("对象拯救成功!");
        }else{
            System.out.println("对象被释放!");
        }
    }
}
运行结果:
finalized执行
对象拯救成功!
对象被释放!

java引用
jdk1.2之前的引用很简单,这里我们不探讨,我们主要探讨jdk1.2之后的引用。
java中将引用分为了:强引用、软引用、弱引用和虚引用。
强引用
强引用在java程序中最常见的一种引用类型,类似Object o = new Object()这类引用,只要强引用还在,垃圾回收器就永远不会回收它。
软引用
软引用通常用来描述一些可以用但非必须的对象,在内存溢出之前会先回收掉软引用相关联的对象,如果回收后内存依然不够,则才会抛出内存溢出异常。
弱引用
弱引用用来描述一些非必须的对象,但是它的强度比软引用还有弱一些。被弱引用关联的对象只能存活到下次垃圾回收器工作之前,当垃圾回收器开始工作时,无论当前内存是否足够,都会回收掉被弱引用关联的对象。
虚引用
虚引用是最弱的一种引用类型,为对像设置虚引用关系的唯一目的就是能在这个对象被垃圾回收之时收到一个系统通知。
垃圾收集算法
1、标记-清除算法
这是最基础的一种垃圾收集算法,后续所有的算法都是在这个算法的基础上进行扩展。
通过算法的名字大致能够看出,该算法分为了“标记”和“清除”两个阶段:首先需要标记出需要回收的所有对象,待标记完成后清除掉所有标记过的对象。这个算法的不足主要有两个:一是性能问题,标记和清除两个阶段的性能都不高,二是标记清除后会产品不连续的大量内存碎片,内存碎片太多会导致下一次在需要分配占用大量内存的对象时,无法找到足够的连续碎片而不得不再一次触发垃圾收集动作。
2、复制算法
为了解决效率问题,复制算法出现了。这种算法会将可用内存区域划分为大小相同的两块,当需要垃圾回收时,会先将可用的对象复制到另一个内存区域,从而将当前区域一次性清除。这样做的好处是每次都将一整块内存区域清除掉,从而避免了大量的内存碎片出现。
目前主流的商用虚拟机大多是采用复制算法来回收新生代。
3、标记-整理算法
当对象的存活率较高时采用复制算法,效率就会很低,因此对于老年代一般不采用复制算法。
鉴于这种问题,一种称之为“标记-整理”算法的思路出现了。它和“标记-清除”算法一样,都需要先进行标记,但是它不会简单一次性清除标记的对象,而是将所有存活对象都移动到另一端,然后清除掉边界外的对象。
4、分代收集算法
分代收集其实就是将内存划分为几块,比如将java堆划分为新生代和老年代,根据不用年代采取最适合的算法,所以目前主流商用虚拟机都是采用这种方式。
学习交流群:669823128

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

推荐阅读更多精彩内容