大家好,又见面了,我是你们的朋友全栈君。
1 JDK1.7结构
1.1 JVM内存图
- 程序计数器: 线程私有的(每个线程都有一个自己的程序计数器), 是一个指针. 代码运行, 执行命令. 而每个命令都是有行号的,会使用程序计数器来记录命令执行到多少行了.
- Java虚拟机栈: 线程私有的(每个线程都有一个自己的Java虚拟机栈). 一个方法运行, 就会给这个方法创建一个栈帧, 栈帧入栈执行代码, 执行完毕之后出栈(弹栈), 存的是对象的引用.
- 本地方法栈: 线程私有的(每个线程都有一个自己的本地方法栈), 和Java虚拟机栈类似, Java虚拟机栈加载的是普通方法,本地方法加载的是native修饰的方法. **native:**在java中有用native修饰的,表示这个方法不是java原生的.
- 堆: 线程共享的(所有的线程共享一份). 存放对象的,new的对象都存储在这个区域.
- 方法区: 线程共享的(所有的线程共享一份), .class的信息, 类的信息, 方法的定义, 常量池, 静态变量等.
1.2 JDK1.7 堆内存结构
- Young 年轻区(代) Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区.
- Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用.
- 在Eden区间变满的时候, GC就会将存活的对象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到Tenured区间。
- Tenured 年老区
- Tenured区主要保存生命周期长的对象,一般是一些老的对象.
- 当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。
- Perm 永久区 Perm代主要保存class,method,filed对象,这部份的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。
- Virtual区: 最大内存和初始内存的差值,就是Virtual区。
这里提到的GC咱们后续继续介绍~
2. JDK1.8 结构
2.1 JVM运行时内存图
JDK1.8和JDK1.7的jvm内存最大的区别是, 在1.8中方法区是由元空间(元数据区)来实现的,常量池移到堆中. 1.8不存在方法区,将方法区的实现给去掉了.而是在本地内存中,新加入元数据区(元空间). 元空间: 存储.class 信息, 类的信息,方法的定义,静态变量等.而常量池放到堆里存储
2.2 JDK1.8堆内存结构
由上图可以看出,jdk1.8的内存模型是由2部分组成, 年轻代 年老代.
- 年轻代: Eden 2*Survivor
- 年老代:OldGen 在jdk1.8中变化最大的Perm区,用Metaspace(元数据空间)进行了替换. 需要特别说明的是: Metaspace所占用的内存空间不是在虚拟机内部,而是在本地内存空间中,这也是与1.7的永久代最大的区别所在.
- 为什么要废弃1.7中的永久区呢? 现实使用中,由于永久代内存经常不够用或发生内存泄露,爆出异常java.lang.OutOfMemoryError: PermGen。基于此,将永久区废弃,而改用元空间,改为了使用本地内存空间。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/139595.html原文链接:https://javaforall.cn