前言
在开始之前,先了解一下Jdk1.8开始,舍弃内存结构中的永久代及其原因。
(1)jdk1.8 永久代变化图
1. 永久代经常内存溢出,引发 java.lang.OutOfMemoryError: PermGen 异常。
2. 移除 PermGen 可以促进 HotSpot JVM 与 JRockit VM 的融合,因为 JRockit 没有永久代。
根据上面的各种原因,PermGen 最终被移除,方法区移至 Metaspace,字符串常量池移至 Java Heap。
(2)使用Metaspace的优点
Metaspace可以使用本地内存,突破MaxPermSize的大小,解决了JVM执行Java程序,需要创建大量类时,造成FullGC的问题。 后续,详解Metaspace。
图1 图2
(二)切入正题
如上图1,2 为JVM的内存结构:包含堆区、非堆区,接下来分别进行介绍。
1. 堆区
包含年轻代、老年代(Jdk1.7开始,字符串常量池存放在堆区)。
1.1 年轻代(Young)
包含Eden和俩个Survivor(S0,S1)区,默认比例:Eden:S0:S1=8:1:1。其中S0,S1是来回切换的,保存新生代不能被释放的对象,但是S0和S1,总有一个是空的。
1.1.1 Young GC( 后续将详细介绍JVM GC过程)
新对象在Eden区进行分配,若Eden区没有足够空间,JVM将触发一次Minor GC(Young GC),将S0中幸存的对象和Eden不能释放的对象,都放入S1区。
(1)若回收成功,则释放Eden和S0区,多次经过回收(默认15次)还存活的对象,将被存放到Old区。
(2)若多次Minor GC之后,Young区内存还是满的,JVM会抛出:java.lang.outofMemorryError:java heap space。
1.2 老年代(old)
用于存放Young区被多次回收之后存活的对象。当old区没有足够内存进行分配时,JVM将触发Major GC(FUll GC)。
2.非堆区
包括Metaspace,CCS,CodeCache
2.1 Metaspace
主要存放.Class、Package、Method、Field、字节码、常量池、符号引用等。
2.2 CCS(压缩类空间)
只有启动短直针的时候才会存在;在堆中分配的每个对象,都存在一个指向自己的Class的指针,在64位虚拟机中每个指针是64位的,如果使用短直针(32位),其指向的class文件就会存储在CCS中。
2.3 CodeCache
存放JIT编译后的代码和JNI的native代码。