最近读了《深入理解jvm》这本书,对java内存这块自己进行总结了下,感觉这本书讲的很好,强烈推荐

JAVA内存区域

1.运行时数据区域

java虚拟机所管理的内存区域主要划分为以下五个区域。
\"Alt\"

1.1 程序计数器

程序计数器是一块较小的内存空间,可以把它看作是当前线程所执行的字节码的行号计数器,分支、循环、跳转、异常恢复都需要依赖于这个程序计数器。每个线程都有一个独立的程序计数器,成这排尿内存区域为\"\"线程私有的\"内存。

此内存区域是java虚拟机中唯一一个没有规定OutOfMemory的区域

1.2 Java虚拟机栈

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

局部变量表存放了编译期间8种基本数据类型(boolean,int…)、对象引用和returnAddressle类型

如果线程请求栈的深度大雨虚拟机允许的深度,会抛出StackOverflowError异常,申请不到足够的内存时,会抛出OutOfMemory异常

1.3 本地方法栈

与虚拟机栈作用类似,不过本地方法栈是为Native方法服务

1.4 堆

Heap是java虚拟机所管理的内存最大的一块,是所有线程共享区域,用来存放实例对象

按照GC来划分,分为新生代和老年代,再细致一点还有Eden空间、From Survivor空间、To Survivor空间

如果在堆中没有足够的内存去完成实例分配,会抛出OutOfMemory异常

1.5 方法区

是各个线程共享的内存区域,主要用于存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译的代码等数据。

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

2. HotSpot虚拟机对象

2.1 对象的创建过程

1) 执行到new指令时,先检查是否能在常量池定位到类的引用,,检查这个类是否已经被加载、解析和初始化过
2) 为对象分配内存
3) 将分配到的内存空间都初始化为零值
4) 对对象进行必要的设置

2.2 对象的内存布局

对象在内存中的布局可以分为对象头、实例数据和对象填充

对象头包含两部分数据
一部分用于存储对象本省的运行时数据,如哈希码、GC分代年龄等
另一部分是类型指针,循迹迹通过这个指针来确定对象是哪个类的实例

实例数据存储的是对象真正的有效数据,也是代码中所定义的各种类型的字段内容

对齐填充主要是起占位符的作用

2.3 对象访问定位

java程序通过栈上的reference引用来获取堆上的具体对象,目前主要有两种方式去访问对象,句柄和直接指针

句柄方式
reference引用存放的是句柄地址,句柄中存放了对象实例数据和类型数据的具体地址
如图:
\"Alt\"

直接指针
reference引用存放的是对象地址
如图
\"Alt\"

收藏 打印