深入理解Java虚拟机-GC&运行时数据区

系列阅读
1.深入理解Java虚拟机-GC&运行时数据区
2.深入理解Java虚拟机-类文件结构及加载
3.深入理解Java虚拟机-内存模型及多线程

1. Java虚拟机概念

JDK(Java Developement Kit)
包括Java程序设计语言、Java虚拟机、Java API类库。
JRE(Java Runtime Environment)
包括Java虚拟机和Java API类库中的Java SE API子集。
JVM(Java虚拟机)
是指一种能够运行Java字节码的虚拟机。Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统,屏蔽了与具体操作系统平台相关信息。
HotSpot VM
是Sun JDK和Open JDK中所带的虚拟机,为目前使用范围最广的Java虚拟机。OpenJDK是JDK的开源版。Sun JDK归Oracle所有。Unix内置或者通过软件源安装JDK的话,一般是Open JDK。参考

2. Java虚拟机运行时数据区

运行时数据区

程序计数器
是当前线程所执行的字节码的行号指示器,在分支/循环/跳转/异常处理/线程恢复等有应用。

Java堆
用于分配和存放对象实例。

虚拟机栈
也称Java栈,描述Java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
注意:如果局部变量是一个reference类型,它引用的对象在Java堆中可被各个线程共享,但是reference本身在Java栈的局部变量表中,它是线程私有的。

本地方法栈
与虚拟机栈作用相似,但本地方法栈为虚拟机使用到的Native方法服务,虚拟机栈为Java方法(字节码)服务。

方法区
主要存放类的元数据,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 运行时常量池是方法区的一部分。

直接内存
不是虚拟机运行时数据区的一部分。NIO(New Input/Output)类是基于通道和缓冲区的I/O方法,使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用来进行操作。

垃圾回收器可以对方法区,Java堆和直接内存进行回收.

扩展
HotSpot虚拟机不区分虚拟机栈和本地方法栈。
线程具有独立的程序计数器和Java虚拟机栈。
方法区和Java堆是被所有线程共享的内存区域。
局部变量表在栈帧中,用于保存函数的参数和局部变量.
在JDK1.6/1.7中,方法区可以理解为永久区(Perm),但是在JDK1.8中,永久区被替换成元数据区.

3. OOM

OOM有memory leak和memory overflow两种情况。
-Xoos:设置本地方法栈大小
-Xms:堆起始容量
-Xmx:堆最大容量
-Xmn: 新生代大小
-XX:PermSize:永久代(方法区)的初始大小
-XX:MaxPermSize:永久代(方法区)的最大值
-Xss:每个线程堆栈容量,JDK1.5+使用,直接决定函数调用的最大深度。

发生OOM的运行时数据区域
程序计数器是唯一没有规定任何OOM情况的运行时数据区域。
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
如果虚拟机栈或本地方法栈可以动态扩展且扩展时无法申请到足够的内存将抛出OutOfMemoryError异常。
如果堆或方法区中没有内存完成实例分配且堆也无法再扩展时将抛出OutOfMemoryError异常。

4. GC(Garbage Collection)

对象创建与回收
判断是否需要类加载-分配内存-内存空间初始化-对象信息设置-对象赋值
HotSpot VM内存管理系统要求对象起始地址必须是8字节的整数倍。
任何一个对象的Finalize()方法都只会被系统自动调用一次,建议不用。

确定对象是死是活的算法

  • 引用计数法
    使用引用计数器对对对象的引用数进行记录,为0时对象不再使用。缺点是难以解决对象之间相互引用的关系,这个时候互相引用的对象实际上应该被回收,但是因为引用数不为0所以判断失误。

  • 可达性分析算法
    从一系列“GC Roots”对象向下遍历,此路径称为引用链。当一个对象到GC Roots没有任何引用链相连(对象不可达)时,则此对象不可用。为Java/C#/Lisp的主流实现。

新生代与老生代
Java堆分为新生代和老年代,新生代被分为三个区域:Eden、From Survivor、To Survivor。

Java堆内存大小划分

新生代可用区域是Eden + From Survivor,一般是Java对象申请内存及存放的地方。老年代一般存放在新生代中已存活许久的Java对象。


Java堆内存模型

垃圾收集器

HotSpot虚拟机的垃圾收集器

新生代大部分要回收,GC一般采用复制算法,快。老年代大部分不需要回收,GC一般采用标记-清除或者标记-整理算法。

  1. Serial收集器
    运行在Client模式下的虚拟机,对新生代进行单线程地暂停收集。采用复制算法。

  2. ParNew收集器
    是Serial收集器的多线程版本,关注点是尽可能地缩短垃圾收集时用户线程停顿的时间。采用复制算法。

  3. Parallele Scavenge收集器
    是多线程收集器,采用复制算法。目的是达到一个可控制的吞吐量(吞吐量=运行用户代码时间/(运行垃圾收集器时间+运行代码时间))。

  4. Serail Old收集器
    是Serial收集器的老年版本。采用标记-整理算法。

  5. Parallele Old收集器
    是Parallele Scavenge收集器的老年版本。采用标记-整理算法。

  6. CMS(Concurrent Mark Sweep)收集器
    是一种以获取最短回收停顿时间为目标的收集器。采用标记-清除算法。

  7. G1(Garbage-First)收集器
    是一款面向服务端应用的垃圾收集器。Java堆布局中的新生代和老生代不再物理隔离。具备如下特点:并行与并发;分代收集;空间整合;可预测的停顿。G1分代/分区.
    G1比CMS有更短的反应停顿时间,但是CMS有更高的吞吐量。但是G1在持续优化。

虚拟机之所以提供多种不同的收集器及调节参数,是因为只有根据实际应用需求和实现方式选择最优的收集方式才能获取最高的性能。

JVM参数
UseSerialGC 新生代和老年代都串行收集
UseParallelGC 新生代ParallelGC,老年代串行
UseParNewGC 新生代ParNew,老年代串行
UseParallelOldGC 新生代parallelGC,老年代ParallelOld
UseConcMarkSweepGC 新生代ParNew,老年代CMS+串行收集器
UserG1GC 使用G1回收器

GC模式

  1. Partial GC:并不收集整个GC堆的模式
    • Young GC:只收集young gen的GC。通常与与Minor GC等价。
    • Old GC:只收集old gen的GC。只有CMS的concurrent collection是这
      个模式
    • Mixed GC:收集整个young gen以及部分old gen的GC。只有G1有这个
      模式
  2. Full GC:收集整个堆,包括young gen、old gen、perm gen(永久代,如果存在的话)等所有部分的模式。Major GC通常是跟full GC是等价的。经常会伴随至少一次的Minor GC,但不绝对。
    System.gc()默认触发Full GC。FullGC会造成Stop-The-World(Java用户执行线程停顿)。

对于GC分类并无完全准确的定义,所以不必纠结。参考

内存分配及回收策略

  • 对象优先在新生代Eden区中分配,当Eden区没有足够空间分配时将发起一次Minor GC。
  • 大对象直接进入老年代。
  • 长期存活的对象将进入老年代。
    根据对象的对象年龄(Age)计数器,从Eden出生并经过一次Minor GC仍存活,且被Survivor空间容纳,则将被移动到Survivor空间中,Age设为1。以后在Survivor区每熬过一次Minor GC,则Age加1,达到限制则晋升老年代。
  • 动态年龄对象判断
    如果Survivor空间中相同年龄所有对象大小总和大于Survivor空间的一半,则年龄大于或等于该年龄的对象可直接进入老年代。
  • 空间分配担保
    新生代使用复制收集算法时,当Survivor空间无法容纳Minor GC存活对象时,需要老年代进行分配担保,将这些对象直接进入到老年代。
    但是老年代剩余空间要足够,为应对此风险,只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。

注:主要内容摘录自书籍 深入理解Java虚拟机,周志明 著

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