您的位置:首页 > 编程语言 > Java开发

Java内存区域

2016-08-08 15:32 274 查看
运行时数据区域:

1、程序计数器:和计算机组成里面的PC有点类似,表示当前程序所执行的字节码的行号指示器。由于java的多线程实现是通过线程轮流切换来完成的,所以每一个线程都必须有一个线程计数器用来保存本线程的字节码行号,以便切换后能恢复到正确的执行的位置。这个计数器是存在于每一个线程自己私有的内存区域,互不影响,我们称这类内存区域为“线程私有”的内存。该内存区域是唯一个不会发生OOM异常的java内存区域。

2、栈区:1)java虚拟机栈区,它也是线程私有的,其生命周期和线程周期相同。虚拟机栈描述的是java方法执行的内存模型,每一个方法的相关信息(变量表、操作数栈等)都被存入一个栈帧(Stack Frame)中,每一个方法的调用到执行完成都表示一个Stack Frame在虚拟栈中的进栈出栈。2)本地方法栈:与虚拟栈类似,其区别在于虚拟机栈为JVM执行java方法(字节码)服务的,而本地方法栈则是为JVM使用到的Native方法服务的。

3、堆区:所有对象的实例和数组都必须在堆内存中分配内存,Java堆是被所有线程共享的一个内存区,在虚拟机启动时创建。也就是说,对于对象来说,其引用是存在栈区的,其对象本身则是存放在堆区的。

4、方法区:用于存储已被虚拟机加载的类信息,静态变量、常量、即时编译的代码数据的内存区域。

Java对象:

1、Java对象的创建:代码层面上来说一般是一条new指令,虚拟机遇到一条new指令后:

1)首先去检查该类是否被加载、解析和初始化过。

2)类加载后,是要为该对象在堆区分配内存。这里需要注意的是分配有两种方式:a、指针碰撞方式:java内存规整的情况下使用该方式。b、空闲列表:有点类似OS中的内存管理,该列表记录了哪些内存时可用的,分配时选择一块足够大的内存给对象,一般用于内存不规整的条件下。

3)分配内存后,虚拟机需要将分配的内存都初始化为零值(不包括对象头)。保证了实例字段可以不赋值就可以使用。

4)接下来虚拟机会为对象头设置相关信息(如这个对象属于哪个类,对象的hash码、对象的GC分代年龄等)。

5)上述4步已经完成了JVM层面上的对象创建,但是程序层面上的对象创建还未完成,还需要一个init的过程(按照程序猿的意愿完成对象信息的初始化)。

2、对象的内存布局:

对象在内存中存储的布局含三个部分:对象头(Header),实例数据(Instance Data)和对齐填充(Padding)。

1)对象头:

a、用于存储对象运行时本身的数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁等。

b、另一部分是类型指针,用于对象指向它的类元数据的指针,虚拟机通过这个指针来找到该对象属于哪个类的实例。

2)实例数据部分:对象真正存储的有效信息,不论是从父类继承下来的,还是子类本身就有的都需要记录下来。

3)对齐填充:对象起始地址必须是8字节的整数倍,当对象的实例数据部分没有对齐时,需要进行填充。

3、对象的访问定位:句柄和直接指针,具体实现和虚拟机实现有关。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 内存