JVM模型介绍
1.JVM 为什么使用元空间替换了永久代?
这里引入知乎
码上技术指导老师-回答
点击超链接,可以查看原文。
这里我对原文做一些自己的提炼,用自己的话说明白即可。
(1)JDK 7 之前JVM模型
可以看到,堆和方法区物理上是连接在一起的,但是逻辑运行层面是隔离的。
我们绝大多数用的虚拟机是Hotspot版本的虚拟机,其结构如下:
- 堆和方法区是物理连续而不是逻辑运行连续
- 方法区位于永久代之中
- 永久代和堆是逻辑上隔离的,物理上连续的,同1。
Java 7 → Java8 中数据存储位置转移如下: - 符号引用——Native Memory
- 字符串常量池——Java Heap
- 类的静态常量——Java Heap(JDK 7)——元空间(JDK 8)
- 永久代参数:(只在JDK7以及之前生效)
-XX:PermSize -XX:MaxPermSize - 年轻代参数:
-Xmn:
题目:
这里显然指的是JDK7,
-Xms 堆内存的初始大小,默认为物理内存的1/64。一般来讲,大点,程序会启动的快一点。
-Xmx 堆内存的最大大小,默认为物理内存的1/4。如果程序运行需要占用更多的内存,超出了这个设置值,就会抛出OutOfMemory异常。
-Xmn 堆内新生代的大小,其中包含1个Eden区2个Suvivor区,通过这个值也可以得到:
老年代的大小 = -Xmx减去-Xmn
-Xss 设置每个线程可使用的内存大小,即栈的大小。这个就要依据你的程序,看一个线程大约需要占用多少内存,可能会有多少线程同时运行等。
解析:
最小内存值是-Xms 所以是1024M
-XXSurvivorRatio=3
1个Eden : 1个Suvivor = 3 : 1
而Survivor区有2个,所以总共占用5份内存空间,-Xmn是堆内新生代的大小,那么5120M是新生代的总大小,Suvivor = (5120 / 5) * 2 = 2048M
所以答案是D
(2)JDK 8 之后JVM模型
HotSpots取消了永久代,方法区存在于元空间(Metaspace)。同时,元空间不再与堆连续,而且是存在于本地内存(Native memory)。
我们知道当堆内存空间不够时会触发GC垃圾回收,但是Native memory空间不够却不会触发GC。
-XX:MetaspaceSize,class metadata的初始空间配额,以bytes为单位,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当的降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize(如果设置了的话),适当的提高该值。
-XX:MaxMetaspaceSize,可以为class metadata分配的最大空间。默认是没有限制的。
-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为class metadata分配空间导致的垃圾收集。
-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为class metadata释放空间导致的垃圾收集。
(3)总结
- 表面上看是为了避免OOM异常。因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。
- 更深层的原因还是要合并HotSpot虚拟机和JRockit虚拟机的代码,JRockit从来没有所谓的永久代,也不需要开发运维人员设置永久代的大小,但是运行良好。