大白话讲清楚JVM里的方法区、永久代以及元空间
在JDK1.8以及之后的版本中JVM的运行时数据区的结构发生了变化
其中最大的变化就是关于方法区的,比如去除了永久代,换上了元空间,并且元空间不再与堆连续,而是使用的本地内存,并把StringTable 串儿池移入了堆内,等等。
说到方法区,很多人一直搞不清楚,方法区、永久代以及元空间,这几个东西它们之间到底有什么关系?
今天就用通俗易懂的大白话来讲一讲
1、搞清楚 方法区、永久代以及元空间之间的关系
首先,我们看一下JVM运行时数据区的结构图
从上图可以看出,JVM的规范中,是把整个运行时数据区,分为了:堆、栈、方法区、程序计数器和本地方法栈。
接下来,我们先来理解两个概念:规范和实现
针对Java虚拟机的实现有专门的《Java虚拟机规范》,在遵守规范的前提下,不同的厂商会对虚拟机进行不同的实现。 就好比开发的过程中定义了接口,具体的接口实现大家可以根据不同的业务需求进行实现。
我们通常使用的JDK都是由Sun JDK和OpenJDK所提供,这也是应用最广泛的版本。
而该版本使用的JVM就是HotSpot VM。通常情况下,我们所讲的Java虚拟机指的就是HotSpot虚拟机。
了解了规范和实现的概念后,接下来,我们继续讨论 方法区
那方法区、永久代以及元空间,这几个东西它们之间到底有什么关系?
其实很简单!
方法区就是JVM里的规范,意思就是JVM规范里要求那些JVM的厂商们在实现JVM时必须有方法区这个东西,它就是个规范,规定。就相当于Java代码里的接口。
那是规范(接口)的话,就肯定要有具体的实现
那方法区的具体实现是什么呢?
简单来说,在HotSpot 虚拟机中 JDK1.6以及之前,方法区的具体实现是 永久代 PermGen
在JDK1.8以及之后,方法区的具体实现是 MateSpace元空间。
1.6和1.8都说完了,那1.7呢?
其实在1.7的时候就已经慢慢的开始去永久代化了,1.7中永久代中存储的部分数据已经开始转移到Java Heap 堆或Native Memory 本地内存中了。
比如,符号引用(Symbols)转移到了Native Memory;字符串常量池(StringTable)转移到了Java Heap;类的静态变量(class statics)转移到了Java Heap。只是在1.7的时候永久代这个概念还在,没完全去除,然后在1.8的时候,完全去除了永久代。
好,到这里,我想我已经讲清楚了。方法区、永久代以及元空间的关系就这么简单
2、堆和方法区的物理存储
为了更细化的讲解,我们将第一张图进行进一步的优化调整,调整后,如下图
从上图可以看出,堆和方法区是连在一起的。但这并不能说堆和方法区是一起的,它们在逻辑上依旧是分开的,但在物理上来说,它们又是连续的一块内存。也就是说,方法区和前面讲到的Eden和老年代是连续的。
3、永久代(PermGen)
对于习惯了在HotSpot虚拟机上开发、部署的程序员来说,很多都愿意将方法区称作永久代。
本质上来讲两者并不等价,仅因为Hotspot将GC分代扩展至方法区,或者说使用永久代来实现方法区。在其他虚拟机上是没有永久代的概念的。也就是说方法区是规范,永久代是Hotspot针对该规范进行的实现。
理解上面的概念之后,我们对JDK1.7及以前版本的堆和方法区的构造再进行一下变动。
再重复一遍,就是对JDK1.7及以前版本的Hotspot中方法区的具体实现是永久代。
同时,永久代和堆逻辑上是相互隔离的,但它们使用的物理内存是连续的。
永久代的垃圾收集是和老年代捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。
但在JDK1.7中永久代中存储的部分数据已经开始转移到Java Heap或Native Memory中了。比如,符号引用(Symbols)转移到了Native Memory;字符串常量池(interned strings)转移到了Java Heap;类的静态变量(class statics)转移到了Java Heap。
然后,在Java8中,时代变了,Hotspot取消了永久代。永久代真的成了永久的记忆。永久代的参数-XX:PermSize和-XX:MaxPermSize也随之失效。
4、元空间(MateSpace)
对于JDK1.8,HotSpots取消了永久代,那么是不是就没有方法区了呢?当然不是,方法区只是一个规范,只不过它的实现变了。
在JDK1.8中,元空间(Metaspace)登上舞台,方法区的具体实现换成了元空间(Metaspace)。
同时,元空间不再与堆连续,而且是存在于本地内存(Native memory)
本地内存(Native memory),也称为C-Heap,是供JVM自身进程使用的。当Java Heap空间不足时会触发GC,但Native memory空间不够却不会触发GC。
针对JDK1.8的调整,我们再次对内存结构图进行调整
元空间存在于本地内存,意味着只要本地内存足够,它不会出现像永久代中“java.lang.OutOfMemoryError: PermGen space”这种错误。看上图中的方法区,是不是“膨胀”了。
默认情况下元空间是可以无限使用本地内存的,但为了不让它如此膨胀,JVM同样提供了参数来限制它使用的空间。
- -XX:MetaspaceSize,class metadata的初始空间配额,以bytes为单位,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当的降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize(如果设置了的话),适当的提高该值。
- -XX:MaxMetaspaceSize,可以为class metadata分配的最大空间。默认是没有限制的。
- -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为class metadata分配空间导致的垃圾收集。
- -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为class metadata释放空间导致的垃圾收集。
5、永久代为什么被替换
思考一下,为什么使用元空间替换永久代?
1、为永久代设置空间大小很难确定。
一个应用动态加载的类的多少是很难确定的,如果永久代设置的过小,会频繁触发FullGC,并且可能会出现OOM。
而元空间的大小只收本地内存限制,这样出现OOM的机会比较小。
表面上看是为了避免OOM异常。因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,但是,不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。
当使用元空间时,可以加载多少类的元数据就不再由MaxPermSize控制, 而由系统的实际可用空间来控制。
2、对永久代进行调优十分困难。
调优是为了减少FullGC,如果永久代频繁触发FullGC,会使永久代调优变得困难
3、更深层的原因还是要合并HotSpot和JRockit的代码,JRockit从来没有所谓的永久代,也不需要开发运维人员设置永久代的大小,但是运行良好。同时也不用担心运行性能问题了,在覆盖到的测试中, 程序启动和运行速度降低不超过1%,但是这点性能损失换来了更大的安全保障。
6、StringTable为什么要放到堆
因为永久代的回收频率比较低,只在FullGC
的时候才会被回收,FullGC
只会在老年代或者永久代空间不足时才会触发。如果有大量的字符串被创建,放在永久代,由于永久代的回收频率低,会导致很多无用的字符串得不到及时的回收,而导致永久代空间不足。如果放到堆里,能够及时回收内存。
大白话讲清楚JVM里的方法区、永久代以及元空间相关推荐
- JVM(5)_方法区和大厂面试题
文章目录 1. 堆.栈.方法区的交互关系 2. 方法区的理解 3.设置方法区大小与OOM 3.1 方法区大小 3.2 方法区OOM 4.方法区的内部结构 4.1 方法区中存储的信息 4.2 运行时常量 ...
- JDK1.8 JVM元数据区取代了永久代,元数据空间并不在虚拟机中,而是使用本地内存
JDK1.8 JVM运行时内存数据区域划分.1.8同1.7比,最大的差别就是:元数据区取代了永久代.元空间的本质和永久代类似,都是对JVM规范中方法区的实现.不过元空间与永久代之间最大的区别在于:元数 ...
- JVM运行时数据区域——为什么jdk8用元空间替换了永久代
以局部窥全局,这个问题其实很复杂,要弄清楚这个问题,首先要对JVM运行时数据区域划分以及各个数据区域的作用了和指掌. JVM运行时数据区域总览 JVM在执行Java程序的过程中(简称运行时)会把它所管 ...
- JVM堆 栈 方法区详解
一.栈 每当启用一个线程时,JVM就为他分配一个JAVA栈,栈是以帧为单位保存当前线程的运行状态 栈是由栈帧组成,每当线程调用一个java方法时,JVM就会在该线程对应的栈中压入一个帧 只有在调用一个 ...
- JVM—堆栈 堆 方法区 静态区 final static 内存分配
原文作者:一夜丶鱼龙舞 原文地址:JAVA 堆栈 堆 方法区 静态区 final static 内存分配 详解(转) 一.栈(stack)和堆(heap) (1)内存分配的策略 按照编译原理的观点,程 ...
- 下午花一小时整理的JVM运行时方法区
转载于:https://blog.51cto.com/8745668/2391688
- JVM之 方法区、永久代(PermGen space)、元空间(Metaspace)三者的区别
文章目录 0.前言(JVM 运行时区域) 1.PermGen(永久代) 2.Metaspace(元空间) 3.JDK6 .JDK7.JDK8 内存溢出的示例 4.元空间与本地内存 5.总结 0.前言( ...
- JVM之方法区、永久代(PermGen space)、元空间(Metaspace)三者的区别
JVM体系结构 根据 JVM 规范,JVM 运行时区域大致分为 方法区.堆.虚拟机栈.本地方法栈.程序计数器 五个部分. 1).方法区 方法区是JVM 所有线程共享. 主要用于存储类的信息.常量池.方 ...
- java方法区超详细汇总,方法区到底是干什么用的?不懂方法区不能说了解jvm!
目录 一.运行时数据区结构图 二.栈.堆.方法区的交互关系 三.方法区的理解 官方文档 方法区在哪里 方法区的基本理解 HotSpot中方法区的演进 四.设置方法区大小与OOM 设置方法区内存的大小 ...
- 36.JVM内存分哪几个区,每个区的作用是什么、如和判断一个对象是否存活、java垃圾回收机制、垃圾收集的方法有哪些、java类加载过程、类加载机制、双亲委派、Minor GC和Major GC
36.JVM内存分哪几个区,每个区的作用是什么? 37.如和判断一个对象是否存活?(或者GC对象的判定方法) 38.简述java垃圾回收机制? 39.java中垃圾收集的方法有哪些? 40.java类 ...
最新文章
- 大咖分享会 | 百度首次揭秘如何构建用户画像与移动统计
- html请求接口_python接口自动化测试 - 2.Django开发接口
- Servlet容器中web.xml配置context-param与init-param
- mysql linux root密码忘记了怎么办_linux下忘记mysql root密码解决办法
- Java的接口及实例(转)
- bzoj 1671: [Usaco2005 Dec]Knights of Ni 骑士(BFS)
- [渝粤教育] 西南科技大学 机床电气控制技术 在线考试复习资料
- 关于UIAlertAction如何修改sheet上的字体颜色
- 软件开发流程知识概括
- 董明珠这一年:格力造芯与银隆困局
- 某数5代Cookies生成算法分析
- 今年AI论文8大领域突破:特斯拉自动驾驶入选,视频博主最利好,跨界输出很潮流...
- 扔鸡蛋问题-方程-动态规划
- hpm1005能扫描不能打印_laserjet m1005 mfp 在win10 64位机上不能打印,能扫描
- mstsc解决远程桌面连接提示远程终端连接数超过了允许连接数
- 虚假谣言,新闻的检测与分析论文
- 北大青鸟java第二次月考笔试_北大青鸟ACCP 4.0一期笔试模拟题二(后24题)...
- v16_G120调试电机优化编程
- 今年行情这么差,到底如何进大厂?
- java 获取home路径_关于JAVA_HOME等引用路径