Java运行时数据区域学习笔记

一、Java运行时数据区域

java运行时数据区域主要分为以下几个部分
在这里插入图片描述

1.程序计数器

程序计数器用来存储当前Java指令运行的位置,并指向下一条指令,占用的内存空间较小。对于一个处理器,Java多线程是通过划分时间片,在线程间切换来实现的,因此同一时间只有一个线程的指令在执行。所以每个线程都要有一个独立的程序计数器,保证切换到它时可以正确的执行下一条指令。如果执行的是java方法,这个计数器记录的是虚拟机字节码指令地址,如果是native方法,这个计数器是空值。

2.Java虚拟机栈

java虚拟机栈也是线程私有的,描述的是java方法执行的内存模型。每个方法执行都会创建一个栈帧,用于存储局部变量表,方法出口,操作数栈,动态链接等与该方法相关的信息。一个方法从开始到结束就对应一个栈帧在Java虚拟机栈中从入栈到出栈的过程。

3.本地方法栈

本地方法栈与Java虚拟机栈类似,不同的是本地方法栈为native方法服务。

4.Java堆

堆是线程共有的存储空间,存储一个应用中所有对象的实例,几乎所有的对象实例都在这里分配内存,在虚拟机启动时创建。根据对象 的年龄,分为新生代和老年代。由于是GC发生的主要区域,因此也叫GC堆。Java堆可以处于物理上不连续的内存空间。

5.方法区

方法区也是线程共有的存储空间,存储虚拟机加载的类信息,常量,静态变量等信息。常量池也是方法区的一部分,class文件中用到的字符串常量一般是到常量池的索引,以便节省存储空间。常量不仅仅在编译器进入常量池,程序运行期也可以将常量放进常量池中。

二、 对象

1.创建

Java面向对象,实例化一个对象在程序中通过new关键字实现,在JVM中主要分为以下几个步骤
在这里插入图片描述

(1)分配内存

分配内存在堆上实现,由于堆在物理存储上可以不连续,所以主要有两种内存分配机制:
1.如果堆是连续的,那么存在一个指针,其一侧为已经使用的空间,另一侧是未使用的,为对象分配内存就可以通过移动该指针实现。
2.如果堆不是连续的,JVM内部维护一个列表,记录了堆上哪些空间可用,哪些空间不可用,在分配内存时候找到足够该对象使用的内存标记,并更新列表。
这里还要考虑线程安全问题,要保证多个线程并发创建对象不出现错乱,这里主要有两种机制:
1.对分配内存空间的动作进行同步
2.对堆分区,每个线程对应一块区域,线程为对象分配内存时在自己的内存块中分配,自己内存块使用完再同步申请外部内存空间。

(2)内存区域初始化为零值

分配完区域之后要对拿到的内存区域初始化为零值,从而保证实例字段在不赋值的情况下也可以直接使用,只不过访问到的是该字段对应的零值。

(3)对对象进行必要的设置

接下来对对象头进行设置,比如该对象是哪个类的实例,对象的hashcode,对象的GC分代年龄等。

(4)对字段赋值

到这里才开始执行在构造器中指定的字段赋值。JVM执行new指令后执行 init 方法,把对象按照我们写的样子进行赋值,到这里一个对象才完整的产生出来。

2.布局

一个对象主要分为三部分:对象头, 实例数据,对象填充。

(1)对象头

hotspotVM中对象头分为两部分,一部分用于存储对象自身的运行时数据,比如hashCode,GC分代年龄,线程持有的锁等等。另一部分是类型指针,用以指定是那个对象的实例,如果是对象数组,还要指定数组的长度。

(2)实例数据

这部分区域存储的是该实例真正的有效信息,就是我们在代码中定义的各个字段,包括父类和对象本身的字段。

(3)对象填充

hotspotVM要求对象起始地址是8的整数倍,也就是对象大小必须是8的整数倍。所以如果大小不够的话需要填充补齐。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值