目录
- 概述
- 运行时数据区域
2.1.程序计数器
2.2.Java虚拟机栈
2.3.本地方法栈
2.4.堆
2.5.方法区
2.6.运行时常量池 - 对象创建过程
1.概述
众所周知,Java虚拟机会自动管理内存资源,在开发过程中不易出现内存泄漏或内存溢出问题。首先,我们先来了解一下什么是运行时数据区域,Java程序执行时,会先将.java源文件通过编译器编译为字节码文件 .class文件。然后由JVM的类加载器加载各个类的字节码文件,最后由执行引擎执行,在这整个过程中产生运行时数据区域。
2.运行时数据区域
JVM会将所管理的内存分为几个运行时数据区域
-
程序计数器 : 用于指示当前线程所执行字节码的行号,属于线程私有数据区。
如果当前线程正在执行一个Java方法,则计数器记录当前正在执行字节码指令地址。
如果执行的是一个Native方法,则为空。
注意: 程序计数器是Java虚拟机规范中唯一没有规定任何OutOfMemoryError情况的区域。 -
Java虚拟机栈 : 主要存储局部变量表,操作数栈,动态连接,方法出口信息, 线程私有
这里的本地变量存放编译期可知的各种基本类型数据(int , boolean , byte , char , short , float , long , double)、对象引用,在编译期分配所需空间。
注意:当线程请求深度大于虚拟机栈最大深度时,将抛出StackOverflowError,如果虚拟机栈可动态扩展,若扩展时无法请求到足够的内存,将抛出OutOfMemoryError -
本地方法栈: 线程私有,抛出异常情况与虚拟机栈一样。
-
Java堆: 存储所有实例,数组的数据区域,所有线程共享
堆是内存管理中空间最大的一块区域,也是垃圾收集器管理的主要区域。Java堆在物理上可以为不连续的,只需保证逻辑上连续即可。
注意:当堆没有内存完成实例分配,并且无法在扩展时,将抛出OOM -
方法区: 存储被虚拟机加载的类信息,常量,静态变量,线程共享
-
运行时常量池: 属于方法区的一部分,存放编译期生成的各种字面量和符号引用。
注意:当常量池无法再申请到空间时,将抛出OOM
3.对象创建过程
1)当虚拟机执行到new指令时,首先会检查该类是否已被加载、解析和初始化过。如果未加载,先执行类加载过程。
2)类加载完毕后,接下来进行实例对象内存分配。分配方式根据Java堆内存是否规整分为两种:
- 指针碰撞:堆内存规整,只将已使用和空闲内存各放一边,在两者中间分界点放置指示器,每次需要分配空间时就将指示器向空闲内存那边移动。
- 空闲列表:堆内存不规整时,虚拟机维护一个列表,记录着哪些内存块空闲,分配时将足够的内存空间划分给实例对象,并更新列表。
3)内存分配完成后,虚拟机将分配到的内存都初始化零值,设置对象头信息(哪个类的实例、如何找到类的元数据信息,对象哈希码,GC分代年龄等)
4)上述内容执行完之后,紧接着会执行方法,把对象实例数据初始化。