JVM内存包括若干个数据区域,如线程私有的程序计数器、虚拟机栈、本地方法栈;线程共享的方法区、堆。
JVM组成部分
1)、程序计数器
程序计数器即计算机处理器中的寄存器,指向当前线程正在执行的指令地址,类似于书签。程序计数器占用内存空间非常小,几乎可以忽略不计。它保证了多线程情况下,线程进行切换时,程序能快速找到执行的位置。
2)、虚拟机栈
执行方法时会对应生成一个栈帧,栈帧包括局部变量表、操作数栈、动态连接、返回地址、附加信息。虚拟机栈中存放着一个个的栈帧,当前栈帧存在于虚拟机栈的最上面(最先出栈的位置)。虚拟机栈默认大小为1M,可以使用参数-Xss进行设置大小,eg:-Xss1M,栈内存为1M。
局部变量表:存放方法的参数和局部变量;
操作数栈:方法执行在操作数栈中完成,字节码指令会往操作数栈进行写入(入栈)和取出(出栈);
动态连接:符号引用转换成实际地址的引用;
返回地址:举个例子:方法C存在返回值,则方法C执行完后会将返回值的地址返回给方法B;
附加信息:不在虚拟机规范内的信息。
3)、本地方法栈
保存本地方法的信息,本地方法就是使用native修饰的方法,并不是用java写的方法。JVM中调用native方法时,不需要在虚拟机中创建栈帧,而是通过动态链接直接调用native方法本身。
4)、方法区
可以理解为永久代(JDK<=1.7)或者元空间(JDK>=1.8)。一般来说,方法区中存放的是对象不可变的部分,比如:常量、静态变量、类信息、编译后的代码等。永久代设置参数:-XX:PermSize(设置初始内存大小)、-XX:MaxPermSize(设置内存的最大上值)。元空间大小只受机器物理内存影响,理论上元空间的大小为机器物理内存大小,元空间设置参数:-XX:MetaspaceSize(设置元空间扩容时触发FullGC的初始化阈值)、-XX:MaxMetaspaceSize(设置元空间的最大值)。
Q:为什么JDK1.8舍弃永久代,引入元空间?
A:JDK1.7及之前永久代和堆是存放在一起的,堆会限制永久代的大小,容易遇到内存溢出问题;对永久代进行调优比较困难;而元空间是单独开辟的空间,与堆隔离开,有效避免Full GC和OOM问题。
5)、堆
JVM中只有一个堆,没有默认大小,堆中存放的是对象,对象对应着类信息,堆中的信息被所有线程共享。堆与内存分配和回收有关,调优时会使用的参数:-Xms、-Xmx、-Xmn。-Xms 设置程序启动时占用内存大小;Xmx 设置程序运行期间最大可占用的内存大小;-Xmn设置新生代大小。
图解
如果有写的不对的地方,请大家多多批评指正,非常感谢!