一、JVM常见垃圾收集算法

众所周知,在Java中内存的分配和回收都是由java虚拟机(JVM)操作的,我们并不需要像C/C++那样需要手动分配和释放内存,也正是因为有了JVM,才能使跨平台成为了可能。说道垃圾回收,我们先要知道在java中内存有哪些部分和作用。

一、java内存组成

在JVM中,内存主要分为一下几个部分:程序计数器(PC)、方法栈、本地方法栈、堆、方法区

1、程序计数器:

操作系统在线程切换和恢复的时候,必须要记录任务执行的位置,这样,当任务恢复的时候,才知道该从哪里继续执行,程序计数器就是记录程序执行的位置的,可以简单理解成字节码的行号指示器。
因为每个线程都是独立执行的,所以每个线程都有一个程序计数器,意味着,程序计数器是线程私有的。
对于java方法来说,程序计数器记录的是字节码的指令地址,对于native方法来说,它的值为空。
程序计数器是唯一一个不会发生OOM(out of memory)的地方。

2、方法栈

方法栈也叫作虚拟机栈,对每个即将执行的方法,都会为其创建一个栈帧,对于java方法从开始执行,到执行结束,就是一个入栈到出栈的过程。
方法栈包含局部变量表,操作数栈,方法退出地址等。
方法栈是线程私有的。
当内存不够创建新的栈帧的时候,会抛出OutOfMemoryError;当方法栈调用深度超过栈的最大深度时,就会出现StackOverflowError,可以使用-Xss设置栈的大小。

3、本地方法栈

本地方法栈和方法栈很类似,但是只是执行native方法时才会使用,JVM规范并没有对本地方法栈的实现有强制性要求,所以会根据每个JVM的不同有不同的实现。本地方法栈也是线程私有的,同样会抛出OutOfMemoryError和StackOverflowError。

4、方法区

JVM在java类在加载后,会将class文件代表的静态存储结构转换为方法区的可运行结构,并将该结构存储在方法区中。主要存储的是类信息,常量池,类变量和JIT编译后的数据。常量池主要包括字面量和符号引用。字面量比较接近java中常量的概念,比如字符串,final修饰的数据等,而符号引用只要是类和接口的全限定名,字段的名称和描述符,方法的名称和描述符。
方法区中的数据是共享的,对所有线程可见。
常量池在运行时也可以改变,比如调用字符串的intern()方法。
当内存不够分配新的常量空间的时候,也会抛出OutOfMemoryError。

5、堆

堆主要用来存储新对象和数组,前面4部分的内存都是由JVM进行管理和控制,对于开发人员来说,堆是可操作性最高的部分,当创建新的对象时,JVM会根据类信息在堆中分配一块内存给新的对象,当内存不够时,也会抛出OutOfMemoryError,同时,这部分区域也是垃圾收集器重要的收集对象。

二、垃圾收集算法

分配内存很好理解,只要在需要分配内存的地方申请相应的地址空间就可以,但是,内存回收就没这么简单了,需要在程序运行过程中判断对象是否还有用,对于没有用的对象,需要对其占用的空间进行回收。这里我们简单介绍下各种垃圾回收算法及其优劣。

1、引用计数法

引用计数法就是记录对象的引用,用来判断对象是否还有用。对于一个对象,当有别的地方访问它时,引用计数器数值+1,当不再引用它时,计数器-1,当对象的引用计数器数值为0的时候,说明该对象不再被使用,可以被回收。引用计数法实现很简单,只需要对每个对象增加一个计数器即可,但是,对于对象间的循环引用就无能为力了。

2、标记清除算法

为了解决对象间循环引用的问题,有了标记-清除算法,就像它的名字一样,等需要开始垃圾回收的时候,从GC Root开始,GC线程会把引用不到的对象标记出来(循环引用的对象自然就会被标记出来了),然后就把标记过的对象清除,这样就可以释放无用对象所占用的内存了。但是,这里面有一个很严重问题-内存碎片化严重,这样会严重影响内存的利用率。
举个栗子,现在创建一个需要100MB内存的对象,但是内存只剩20MB,不够,所以触发了GC并且清理了120个对象腾出100MB的内存,按说现在120MB的内存已经够了,但多数情况下还是会抛出OOM异常,因为这些对象不是连续存储的,所以清理出来的内存也不是连续的,由于不存在连续的100MB的内存,所以会抛异常。

3、复制算法

复制算法为了解决标记清除算法内存碎片化的问题。复制算法主要工作流程为:
将内存按照一定比例分为两部分(通常为五五分),对象在只其中的一部分创建
在触发GC后,从GC Root开始将能够引用到的对象(有效对象)依次复制到另外一部分
完成所有有效对象的复制后,清除这部分内存
下次GC又从另外一部分内存复制到当前部分内存,清除另一部分内存

这样,内存碎片化的问题就解决了,但是,你会发现,同一时间其实只有一部分内存在使用,另外一部分都是在空闲的,这样导致内存利用率很低(五五分情况下内存利用率最多到50%)

4、标记整理算法

标记整理算法是为了解决标记清除算法内存碎片化和复制算法内存利用率低的问题,它其实也是这两种算法的结合。工作流程如下:
触发GC后,从GC Root开始将有效对象标记出来
将有效对象依次移动到可用内存开始处
将剩余部分内存清

目前看来,标记整理算法解决了前面几种方法的弊端,也没有引入比较严重的新的问题,那么是不是就没有任何问题,成为垃圾收集的银弹了呢?答案是:当然不是。原因在于,前面所说的垃圾回收的过程中,除了GC线程外,jvm会停止所有java程序的运行,在jvm领域也称为stop the world,这样做的好处和坏处都显而易见,好处就是减少了GC的复杂性,坏处就是java应用都被暂时停止,直到GC结束。在GC算法发展的过程中,细心的人会发现,有些对象的生存周期很长,甚至和整个应用的生命周期相同,比如方法区中的类的字节码所对应的结构,以及堆中代表类的Class对象;有的对象生命周期很短,比如方法中申明的变量所引用的对象,在方法结束后即失效。这种根据生命周期长短划分对象,接近应用的生命周期的叫做永久代,生命周期长的叫做老年代,生命周期短的叫做新生代。

5、分代算法

其实分代算法不是一个具体的垃圾回收算法,它只是根据对象生命周期的长短,选择不同的回收算法。比如说,复制算法,如果大多数都是新生代对象,每次复制的对象会很少,那么效率就会比较高;相反,如果大多数对象属于老年代或者永久代,那么每次需要复制的对象就会特别多,效率就会很低。比如标记复制或者标记整理算法,如果是老年代居多,那么每次需要复制或者整理的对象就比较少,相反,如果是新生代居多,需要复制或者整理的内存就会很多,效率自然就低很多。
所以分代算法主要就是根据生命周期的长短选择合适的算法。一般来说,新生代居多合适用复制算法,老年代适合标记复制算法,永久代适合标记整理算法。
所以说在实际应用过程中,应该根据应用的特点选择合适的垃圾收集算法。

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

推荐阅读更多精彩内容