JVM内存布局
小渣渣,如有什么问题欢迎指正。
内存布局
- 程序计数器:当前线程所执行字节码的行号指示器,线程私有。
并发过程中,线程会被阻塞,当被阻塞后获取资源后,通过行号指示器知道运行到了哪一行。 - 方法区(永久代):JVM中类的元数据在Java堆中的存储区域,线程共享。
Java类对应的HotSpot虚拟机中的内部表示也存储在这里,类的层级信息,字段,名字,方法的编译信息及字节码,变量,常量池和符号解析。 - 本地方法栈:为虚拟机使用到的Native方法服务,这些方法的底层实现非Java,而是C++,线程私有。
- 虚拟机栈:分为局部变量表、操作栈、动态链接、方法出口等信息,线程私有。
其中,局部变量表存放了编译期可知的各种基本数据类型、对象的引用(可能是只想对象起始地址的指针,也可能是只想一个代表对象的句柄或者其他可以找到这个对象的位置;操作栈就是线程运算的地方;动态连接:每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,这些应用会在类加载时的解析阶段被解析为直接引用;方法返回地址是用来唯一确定被调用的方法) - 堆:存放对象实例,线程共享,默认大小1024M。
在JDK8之后
符号引用转移到了native heap;字符串常量、类静态变量转移到了堆。
移除了方法区,把方法区中存的其它的东西放入元空间,元空间不在JVM内存中,在本地内存中,因此大小受总内存大小的限制。
移除永久代的原因:
- 字符串存在永久代中,频繁的对字符串操作,容易出现性能问题和内存溢出。
- 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则使堆区域变小,老年代容易溢出。
- 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。