JVM内存结构与GC剖析 2015-08-28 21:02

JVM内存整体结构

  • 程序计数器

线程私有,即每个线程都会有一个,线程之间互不影响,独立存储。 代表着当前线程所执行字节码的行号指示器。

  • 虚拟机栈——相对重要

线程私有,它的生命周期和线程相同。 类似于C/C++中的栈区。描述的是java方法执行的内存模型:每个方法在执行的同时多会创建一个栈帧用于存储局部变量表、操作数栈、动态链表、方法出口等信息 -Xss参数设置栈容量 例: -Xss128k。

  • 本地方法栈

线程私有。同虚拟机栈,只不过本地方法栈位虚拟机使用到的native方法服务。Sun HotSpot虚拟机把本地方法栈和虚拟机栈合二为一。

  • 永久代内存(非堆内存区)——重要

线程共享。保存了Java SE库的类和方法。其主要组成部分是方法区。方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即使编译后的代码等数据。永久代的对象在Full GC时进行垃圾收集。

  • 堆内存区——重要

线程共享。主要用于分配对象实例和数组

  • 直接内存

非JVM管理范畴中的内存。在NIO中,通过native函数直接分配的堆外内存。

堆内存

初始堆内存通过“-Xms”指定,默认是物理内存的1/64(?)。

最大堆内存通过"-Xmx"指定,默认是物理内存的1/4(?)。

默认空余堆内存小于40%时,JVM就会增大堆内存直到-Xmx的最大限制。

默认空余堆内存大于70%时,JVM就会减少堆内存直到-Xms的最小限制。

因此服务器一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小。

堆内存分为年轻代内存和年老代内存

年轻代内存

年轻代内存分为一个Eden区和两个Survivor区

大多数新建的对象都位于Eden区。当Eden区快用完时,会触发Minor GC。所有需要保留下来的对象会被移到Survivor区域。Survivor区域设计为两个,可能就要是为了灵活移动。具体原因不理解。 经过多次Minor GC后,仍被保留下来的对象会被移动到年老代内存区。

年老代内存

年老代内存区保存了经过多次Minor GC后仍被保留下来的对象。如果年老代内存区也快用完了,就会触发Major GC。Major GC成本更高,会花更多的时间。

Stop the world

注意:在GC过程中,不管是Minor GC还是Major GC。所有的Java应用程序代码都是停止运行的。即整个世界是全部静止的。所以在Spark场景会出现心跳超时就是因为内存不足,而触发GC。

参数配置

JVM参数             参数描述
-Xms                设置堆的初始大小。
-Xmx                设置堆的最大值。
-Xmn                设置堆中年轻代的空间大小,剩下的为老年代的空间大小。
-XX:SurvivorRatio   提供Eden区和survivor区的空间比例。
                    比如,如果年轻代的大小为10m并且VM开关是-XX:SurvivorRatio=2,那么将会保留5m内存给Eden区和每个Survivor区分配2.5m内存。默认比例是8。
-XX:NewRatio        提供年老代和年轻代的比例大小。默认值是2。
-XX:PermGen         设置永久代内存的初始大小。
-XX:MaxPermGen      设置永久代内存的最大值。

GC类型

  • Serial GC(-XX:+UseSerialGC)

串行GC。对年轻代和年老代进行垃圾回收,即Minor GC和Major GC。这个模式对占有内存较少的应用很管用。

  • Parallel GC(-XX:+UseParallelGC)

除了会产生N个线程来进行年轻代的垃圾收集外,Parallel GC和Serial GC几乎一样。这里的N是系统CPU的核数。我们可以使用 -XX:ParallelGCThreads=n 这个JVM选项来控制线程数量。并行垃圾收集器也叫throughput收集器。因为它使用了多CPU加快垃圾回收性能。Parallel GC在进行年老代垃圾收集时使用单线程。

  • Parallel Old GC(-XX:+UseParallelOldGC)

和Parallel GC一样。不同之处,Parallel Old GC在年轻代垃圾收集和年老代垃圾回收时都使用多线程收集。

  • 并发标记清除(CMS)收集器(-XX:+UseConcMarkSweepGC)

它是对年老代进行垃圾收集的。CMS收集器通过多线程并发进行垃圾回收,尽量减少垃圾收集造成的停顿。可使用 -XX:ParallelCMSThreads=n JVM选项来限制CMS收集器的线程数量。

  • G1垃圾收集器(-XX:+UseG1GC) G1(Garbage First)

垃圾收集器是在Java 7后才可以使用的特性,它的长远目标时代替CMS收集器。

Java GC监控工具

  1. jstat(JDK自带)
  2. jvisualvm(JDK自带,GUI)

几种GC

Minor GC:清理年轻代的内存。 Major GC:清理年老代的内存。 Full GC:清理整个堆空间(包括年轻代和年老代)和永久代区域的内存。

GC调优

OutOfMemoryError: PermGen space => 增大永久代内存。 大量Full GC操作 => 尝试增大老年代的内存空间。

参考文档

  1. 深入理解java虚拟机(一):java内存区域(内存结构划分)
  2. Java内存与垃圾回收调优
Tags: #Spark #Java    Post on Programming