【JavaSE】JVM的运行时数据区域

一、运行时数据区域

当JVM运行之后,操作系统会将自己内存 堆中的一块空间分配给JVM作为运行时存储数据的区域。因为操作系统栈中的区域可能会被操作系统回收。内存分配图如下(以windows系统为例):
在这里插入图片描述

1.程序计数器

线程私有的,记录此线程当前所执行的字节码的行号指示。(因为Java具有解释型语言的特征,所以用程序计数器去记录解释到某一行的字节码行号)。

2.Java虚拟机栈

线程私有的,当一个线程启动的时候,JVM会给线程分配一块栈空间(可以动态扩展),用来存储程序计数器和运行方法时候的数据。线程每进入一个方法都会在栈区域中开辟一块栈帧空间(开辟的时候栈空间大小已经确定),用来存储局部变量表、操作数栈、动态链接、方法出入口等信息。方法的栈帧空间随着方法结束,也会被收回。

(1)局部变量表

存储方法中的基本数据类型和引用类型,因为基本数据类型的大小是确定的,并且引用类型存储的都是堆中对象的地址。所以局部变量表所需的空间可以在编译期间完成分配。

(2)操作数栈

虚拟机被称为“基于栈的执行引擎”,这个栈就是操作数栈。在解释执行的时候,对于数据的运算和存储操作都是用操作数栈来执行的。比如遇到字节码指令iadd 就是将虚拟机栈顶的两个元素取出来然后相加并再次存储到栈顶中。 istore_2指令的意思 就是取出栈顶的元素,将它的值存储到局部变量表索引为2的下标处。

当一个线程调用的方法数过多,开辟的栈的次数过大,就会抛出StackOverflowError异常。当一个线程在开辟方法栈帧,动态扩展时候虚拟机的栈空间不够用了,就会抛出OutOfMemoryError异常。

3.本地方法栈

执行本地方法的时候,会在这个栈中实现操作。因为Java方法是字节码形式的,所以需要遵循特定的栈帧规则,而本地方法则可以自由实现。

4.Java堆

线程共享的,一般用来存放所有被实例化出来的对象。也是Java主要的垃圾回收区域。虚拟机所管理的最大的一块内存

5.方法区

线程共有的,用于存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。在JDK1.7及之前,将以上信息存储在永久代中。但是在JDK1.8之后,将常量和静态变量移入到堆中,然后类的元数据存储到元空间中。而元空间是一块和堆不相连的空间,由本地内存中划分出来,程序员可以使用参数指定元空间的大小。

(1)为什么移除永久代?

由于永久代的在堆中存储,而堆中的空间有限,如果永久代的空间太小,那么它将会频繁发生Full GC(因为它的GC是和老年代绑定的),并且频繁发生内存不够用。而将永久代空间设置扩大之后,那么老年代的空间就会减少。很难平衡二者大小。

(2)为什么引入元空间?

元空间的大小如果不指定将会动态扩展,它的空间一般够用,并且减轻了GC的压力。

6.直接内存

使用操作系统中的内存,通过native函数分配内存。然后通过java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值