JVM内存区域(运行时数据区)
根据JVM规划,运行时的内存区域划分为五个部分,分别是堆、方法区、程序计数器、虚拟机栈、本地方法栈,其中在jdk1.8之后方法区被移除,取而代之的是元空间(直接内存)
这是jdk1.6的示意图
这是jdk1.8的示意图
下面介绍一下这五部分的主要信息
一、堆(线程共享)
堆是被所有线程共享的一块内存区域,在虚拟机启动的时候创建,主要用于存放对象的实例,堆的内存大小可通过参数-Xmx 和-Xms 来控制,当堆中没有内存分配个实例,就会出现out of memoryError(OOM)异常
二、方法区(线程共享)
方法区也是线程共享的,用于存放被虚拟机加载的类信息,常量、静态变量、运行是常量池等信息
方法区大小也可通过参数进行设置
-XX:PermSize=N //方法区(永久代)初始大小
-XX:MaxPermSize=N //方法区(永久代)最⼤值
方法区也被称为永久代,但是也有的说永久代是方法区的一种实现,在jdk1.8之后,永久代替换成了元空间(直接内存)
把方法区(永久代)替换成元空间的原因是,永久代有一个固定的上线大小,无法进行调整,而元空间使用的是直接内存,受本机内存影响,并且不会出现oom现象,可以使用-XX:MaxMetaspaceSize标志设置元空间的大小。默认值为unlimited,这意味着它只受系统内存的限制
永久代被替换后,原本存在永久代的东西去哪了?
- 运行时常量池(jdk1.7就移到了堆)、静态变量等移到了堆中
- 类信息、编译后的代码数据移动到了元空间
三、程序计数器
程序计数器是线程私有的,每个线程都有自己独立的程序计数器,程序计数器用于记录java程序执行指令的地址,用于记录方法执行到那条指令,哪个位置
四、虚拟机栈
虚拟机栈是线程私有的,虚拟机栈用于存放栈桢,每一个方法的执行都会创建一个栈桢存入虚拟机栈中,且栈桢的信息包括局部变量、操作数、动态链接、返回地址等信息。每一个方法从执行到结束,意味着一个栈桢从出栈到入栈的过程。
通常说的栈,就是虚拟机栈,通常说的存在栈中的变量,就是栈桢中的局部变量。
对于在方法中创建的临时变量(int temp=10)或临时对象(User a=new User()),是基本数据类型的,就直接将变量存储在虚拟机栈中,如果是引用类型的,就将对象的实例存放在堆中,然后将其引用地址存放在虚拟机栈上。
五、本地方法栈
本地方法栈也是线程私有的,作用于虚拟机栈相似,也是存储方法栈桢等信息,但是它是为虚拟机栈使用到的native方法服务,native方法虚拟机栈无法完成,需要本地方法栈服务。