深入理解Java内存模型和Java对象

 2019-12-10 16:02  阅读(942)
文章分类:Java Core

运行时数据区域

Java虚拟机在执行Java程序时会把它所管理的内存划分为多个不同的区域,这些区域的用途和生命周期都不相同。大概如下图:
20191210001503\_1.png
分别介绍下各个数据区域存在的意义以及在JVM内存管理中承担的作用.

虚拟机栈

虚拟机栈是线程私有的,而且它的生命周期和线程相同.虚拟机栈是描述Java方法执行的内存模型。每个方法在执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口信息等,这里主要了解局部变量表部分。

局部变量表存放了编译时可知的各种基本数据类型和对象引用。需要注意的是long和double数据会占用2个局部变量空间,其它的都占一个。局部变量表的大小在编译时已经确定,所以在方法执行时不会改变局部变量表的大小。

虚拟机栈区域会出现StackOverflowError异常和OutOfMemoryError异常。

程序计数器

程序计数器可以看作是当前线程所执行的的字节码的指示器,只占用很小的内存空间。每个线程都需要有一个独立的程序计数器,各个线程之间的计数器互不影响,所以它也是线程隔离的数据区。

程序计数器是JVM中唯一一个没有规定OOM的区域。

本地方法栈

本地方法栈和虚拟机栈非常相似,它们的区别是虚拟机栈执行的是Java方法服务,而本地方法栈执行的是Native服务。

本地方法栈区域也会出现StackOverflowError异常和OutOfMemoryError异常。

Java堆

Java堆是被所有线程共享的,在虚拟机启动的时候创建,它的唯一目的就是存放对象实例。也就是说所有的对象实例和数组都要在堆上分配。

Java堆可以处于物理上不连续的内存空间,只要逻辑上是连续的即可。如果Java堆无法再继续扩展,而又有对象实例未完成分配,将会抛出OutOfMemoryError异常。

方法区

方法区也是各个线程共享的,主要用于存储已被虚拟机加载的类信息、常量、静态变量、编译后的代码等数据。

运行时常量池是方法区的一部分,主要用于存放编译生成的各种字面量和符号引用。

Java对象和内存模型

在知道Java的内存模型之后,就可以更进一步的去了解Java对象的创建以及它在Java内存中是如何存放的。

Java对象的创建

在Java中创建对象主要是通过new关键字,当虚拟机遇到new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用.并检查这个类是否已经被加载 解析和初始化,如果没有先执行类的加载过程。

经过上面的步骤,确定类已经被加载后,JVM就会为新生对象分配内存.对象所需的内存大小在类加载完成后就已经确定,所以只需要在Java堆中划分出确定大小的空间。内存的划分方式分为”指针碰撞”和”空闲列表”。

对象的访问

Java通过栈上的本地变量表的reference数据来操作Java堆上的对象。reference数据可以通过句柄或者指针的方式区访问对象。

通过句柄方式的话,Java堆中会划分出一块内存来存放句柄池,reference中存储的是句柄的地址,如图:

20191210001503\_2.png
指针访问,reference中存储的直接是对象的地址,如图:
20191210001503\_3.png
使用指针访问的速度更快。

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> 深入理解Java内存模型和Java对象

相关推荐