【jvm】内存区域

​ jvm在执行的过程当中会把它所管理的内存划分为若干个不一样的数据区域,这些数据区域中,有些依赖着用户线程的启动和结束而创建和销毁,有些则随着jvm进程的启动而建立java

内存区域

jvm的运行数据区域能够分为两种:线程私有和线程共享数组

线程私有: 每一个线程的私有数据,包括: 程序计数器、java虚拟机栈、本地方法栈jvm

线程共享: 全部线程共享的部分,包括: Java 堆、方法区、常量池spa

jvm内存区域划图示线程

运行时数据区域

程序计数器

程序计数器是较小的内存空间,它能够看作是当前线程所执行的字节码的行号指示器,用来执行选取小一条须要执行的字节码指令,属于线程私有的内存cdn

若是执行的是一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址,若是执行的是Native方法,这个计数器值为空对象

虚拟机栈

虚拟机栈,也是线程私有的,它的生命周期与线程相同,每一个方法在执行时都建立一个栈帧,每一个方法从调用到执行完成,对应着一个栈帧的入栈到出栈blog

虚拟机栈描述的是java方法执行的动态内存模型生命周期

栈帧存储的数据包括: 局部变量表,操做数栈,动态连接,方法出口等信息进程

在虚拟机栈中,规定了两种异常:

  1. 当栈调用深度大于JVM所容许的范围,会抛出StackOverflowError的错误
  2. 当虚拟机栈在扩展内存时没法申请到足够的内存,会抛出OutOfMemoryError异常

本地方法栈

线程私有,与虚拟机栈提供的功能相似,只不过执行的是本地方法,也就是用Native修饰的方法

堆是被线程共享的一块内存区域,随着jvm的启动而建立,用来存放对象实例和数组

这块区域也是GC进行垃圾回收的主要区域,当申请不到空间时会抛出 OutOfMemoryError异常

堆能够细分为新生代和老年代,新生代用来存放存活时间较短的对象,老年代用来存放存活时间较长的对象,新生代还能够细分为一个Eden区和两个Survivor;

方法区

方法区也是被线程共享的一块内存区域,用来存虚拟机中加载的类信息,常量,静态变量,即时编译器编译后的代码等数据

方法区是jvm的规范,而接下来要说的永久代和元空间正式jvm规范的一种实现

永久代(Permanent Space)

在jdk1.7时,方法区被叫作永久代(Permanent Space),因为方法区主要存储类的相关信息,因此对于动态生成类的状况比较容易出现永久代的内存溢出,当永久代出现内存溢出,会抛出java.lang.OutOfMemoryError: PermGen space异常

元空间(MetaSpace)

在jdk1.8中移除了永久代,使用元空间代替,jdk1.7中,存储在永久代的部分数据就已经转移到了堆内存或者是直接内存。但永久代仍存在于jdk1.7中,并没彻底移除,譬如符号引用(Symbols)转移到了直接内存;字面量(interned strings),类的静态变量(class statics)转移到了堆内存

元空间的本质和永久代相似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。所以,默认状况下,元空间的大小仅受本地内存限制,但能够经过如下参数来指定元空间的大小:

  • -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:若是释放了大量的空间,就适当下降该值;若是释放了不多的空间,那么在不超过MaxMetaspaceSize时,适当提升该值。
  • -XX:MaxMetaspaceSize,最大空间,默认是没有限制的,最大内存受本地内存的限制

参考:深刻理解java虚拟机第二版

更多阅读:chenmingyu.top/categories/