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

Java内存区域与内存溢出异常小结

2017-10-07 18:36 204 查看

运行时数据区域

程序计数器

当前字节码的行号指示器

线程私有

栈区

线程私有

Java虚拟机栈

为虚拟机执行Java方法(即字节码)服务

存储局部变量表、操作数栈、动态链接、方法出口等

局部变量表:编译期间完成分配

存储基本数据类型、对象引用

本地方法栈

为执行Native方法服务

HotSpot将本地方法栈和虚拟机栈合一

Java堆

线程共享

目的:存放对象实例

垃圾回收器管理的主要区域

通过-Xmx和-Xms动态扩展

方法区

虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等

内存回收目标主要是针对常量池的回收和对类型的卸载(类型卸载较负载但必要)

运行时常量

存放编译期生成的各种字面量和符号引用

具有动态性:运行期间可以放入新的变量

直接内存

NIO类,可使用Native函数库直接分配堆外内存,通过存储在堆中的DirectByteBuffer对象作为这块内存的引用进行操作

HotSpot虚拟机对象探秘

对象的创建

创建新对象(new 指令),先检查指令的参数能否在常量池中定位到类的符号引用,并检查是否被加载。如果没有,需进行类加载过程

内存分配:

为新生对象分配内存:

内存规整:指针碰撞

内存不规整:空闲列表

并发情况下的线程安全:

对分配内存空间的动作进行同步处理,保证原子性

每个线程在Java堆中预先分配一小块内存,即本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)。在每个线程自己的TLAB上分配内存,只有分配新的TLAB时,才需要同步锁定

对象的初始化和设置:

将分配的内存空间初始化为零值(使用TLAB可以在分配TLAB时初始化)

设置对象头

<init>
方法,将对象按照程序员的意愿初始化

对象的内存布局

对象头Header:存储对象自身的运行时数据

Mark Word:HashCode、GC分代年龄、锁状态标志、线程只有的锁、偏向线程ID、偏向时间戳等

类型指针:指向类元数据的指针,用于确定对象是哪个类的实例(非必要)

对齐填充(非必要):占位符,因为对象必须是8字节的整数倍

对象的访问定位

需要通过栈上的reference数据操作堆上的具体对象

句柄访问:

在堆中划分一块内存作为句柄池,reference中存储对象的句柄地址,句柄中包含对象实例数据类型数据各自的具体地址信息

优点:稳定的句柄,在对象移动(如gc操作)时,不需要改变reference

直接指针访问:

堆对象的布局中需要考虑如何放置类型数据,reference中存储的是对象实例数据地址

优点:速度快,节省了指针定位的时间开销(HotSpot)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: