根据JVM规范,JVM内存(运行时数据区)分为程序计数器,虚拟机栈,本地方法栈,Java堆,方法区(为了与堆区分也称非堆)五大部分。以下分别介绍各部分的作用:
程序计数器(线程私有)
程序计数器是jvm内存中很小一部分 ,是线程执行字节码的行号指示器。如果执行的是java方法则通过改变程序计数器的值选取下一条语句,如果执行的是native方法则为空。
虚拟机栈(线程私有)
每个方法执行是会创建一个栈帧,栈帧保存了局部变量表,操作数栈,动态链接,方法出口。方法的执行和完成,对应一个栈帧在虚拟机栈的入栈和出栈操作。如果线程请求的栈的深度大于虚拟机栈运行的最大深度会报StackOverflowError。
本地方法栈(线程私有)
与虚拟机栈一样,不同的是虚拟机栈针对java方法的调用,本地方法栈针对nativr方法的调用。
Java堆(线程共享)
所有线程共享的一块内存,作用是保存对象实例,堆中的对象分为新生代,老年代,新生代又可以细分未eden和suvivor。java堆是GC垃圾回收主要发生区域。jdk1.7以后把字符串常量从永久代中剥离出来存放在堆中。可以使用-Xms,-Xmx实现动态扩展,当没有足够空间分配给对象实例时会报OutOfMemoryError。
方法区(线程共享)
方法区用于存储被虚拟机加载的类的信息和常量以及静态变量 。jdk1.8以前使用永久代实现方法区,jdk1.8完全废除永久代使用元空间实现。永久代和元空间最大的区别在于永久代在jvm内存中而元空间在本地内存中。类的信息比较难以确定大小(如jsp,会动态编译servlet类)永久代难以指定大小而元空间只受本地内存大小限制。