深入理解Java虚拟机(一): 内存区域

网友投稿 575 2022-05-30

运行时数据区域

Java在运行时会把它所管理的内存划分为若干个不同的数据区域。

方法区(Method Area)

(1)线程共享

(2)存储

类信息

常量

静态变量

即时编译器编译后的代码

(3)非堆

(4)不需要连续的内存

(5)可以选择固定或可扩展

(6)可选择不实现垃圾收集

(7)针对常量池的回收

运行时常量池(Runtime Constant Pool)

a、常量池:存放编译期生成的字面常量和符号引用

b、这些常量池中的数据进入方法区后存放在运行时常量池中

c、动态性:运行期可将新的常量放入池中,例如:String.intern()方法

(8)对类型的卸载

(9)无法满足内存分配需求时会抛出OutOfMemoryError

虚拟机栈(VM Stack)

(1)线程私有

(2)生命周期与线程相同

(3)描述Java方法执行的内存模型

(4)栈帧

a、局部变量表:基本数据类型、对象引用和returnAddress类型(指向一条字节码指令的地址)

b、操作数栈

c、动态链接

d、方法出口

e、64位的long 和double会占用两个局部变量空间,其余的只占一个

f、编译期完成内存分配

g、方法运行期间不会改变局部变量表的大小

h、存储

i、入栈

j、出栈

(5)线程请求的栈深度大于虚拟机允许的深度会抛出StackOverFlowError

深入理解Java虚拟机(一): 内存区域

(6)如果扩展时无法申请到足够内存会抛出OutOfMemoryError

本地方法栈(Native Method Stack)

(1)为本地方法(Native Method)服务

(2)<--> 区别于虚拟机栈:为虚拟机执行Java方法服务。

(3)抛出StackOverFlowError

(4)抛出OutOfMemoryError

堆(Heap)

(1)Java虚拟机所管理的内存中最大的一块

(2)线程共享

(3)虚拟机启动时创建

(4)存放对象实例及数组

(5)垃圾回收管理(GC)主要区域

- 分代算法

| 新生代

eden

from

to

| 老年代

(6)可划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)

(7)可处于物理上不连续的内存空间,保证逻辑连续即可

(8)可通过-Xmx和-Xms控制大小(可扩展)

(9)堆无法再扩展时会抛出OutOfMemoryError

程序计数器(Program Counter Register)

(1)较小内存空间

(2)当前线程的行号指示器

(3)线程私有的内存

(4)唯一一个没有OutOfMemoryError的区域

直接内存(Direct Memory)

(1)NIO中使用基于通道(Channel)与缓冲区(Buffer)的I/O方式,使用Native函数库直接分配的堆外内存

(2)无法满足内存分配需求时会抛出OutOfMemoryError

对象的创建

(1)类加载检查机制

(2)为新生对象分配内存

(3)把一块确定大小的内存从堆中划分出来。

选择方式由Java堆是否规整决定

Java堆是否规整由垃圾收集器是否带有压缩整理功能决定。

由于对象创建是非常频繁的,则在并发情况下不是线程安全的

对分配内存空间的动作进行同步处理

把内存分配的动作按照线程划分在不同的空间中,即TLAB方式。

只有在TLAB用完并分配新TLAB的情况下需要同步锁定

可以使用-XX:+/-UseTLAB来设定

内存规整: 指针碰撞(Bump the Point)

内存不规整 空闲列表(Free List):维护列表并记录哪些是可用的。

(4)将分配到的内存空间初始化为0(不包含对象头)

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

(6)属于哪个类的实例

(7)如何找到类的元数据信息

(8)对象的哈希值

(9)对象的GC分代年龄

(10)这些数据存放在对象头(Object Header)中

(11)对象得到创建,但是所有的字段为零,在执行new之后会立即执行方法

对象的内存布局

(1)对象头(Object Header)

存储对象自身运行时数据(Mark Word),通常在32位和64位的机器上占用32bit和64bit的空间

哈希吗

GC分代年龄

锁状态标志

线程持有锁

偏向线程ID

偏向时间戳

(2)类型指针: 对象指向它的类元数据的指针

a、虚拟机通过这个指针来确定这个对象属于哪个类

b、不是所有的对象实例都保留有类型指针

c、如果对象是数组,还必须有一块用于记录数组长度的数据

(3)实例数据(Instance Data),真正存储的数据

存储顺序受到虚拟机分配策略参数(Fields Allocation Style)和字段在Java源码中的定义顺序影响

(4)对齐填充(Padding)

a、不是必要存在的

b、仅仅起占位作用

对象访问定位

Java通过栈上的引用(reference)数据来操作堆上的具体对象

句柄访问

(1)堆中划分一块内存作为句柄池

(2)reference中存储对象的句柄地址

(3)句柄中包含对象实例数据与类型数据各自的具体地址信息

优点:reference中存储稳定的句柄地址,在对象移动时只会改变句柄中的实例数据指针

直接指针

(1)考虑如何放置访问类型数据的相关信息

(2)reference中直接存储对象地址

优点:速度更快,节省一次指针定位的时间

本文转载自微信公众号【java学习之道】。

Java 存储

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:[mysql] 17.3 mysql MGR监控
下一篇:在Python中初始化:您需要了解的一切
相关文章