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

运行时数据区域

1.程序计数器

程序计数器可以看成是当前线程所执行的字节码的行号指示器,由于多线程的要求,每条线程都有一个独立的程序计数器,这类线程独立储存的内存称为“线程私有”内存

如果线程执行的是本地方法(native),则计数器值为空

2.Java虚拟机栈

Java虚拟机栈也是线程私有的,它的生命周期与线程相同

虚拟机栈面熟的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧用于储存局部变量表、操作数栈、动态链接、方法出口等信息。

我们一般说的Java栈就是指的这里,更多情况下是指其中的局部变量表

局部变量表存放了各种基本数据类型、对象引用和returnAddress类型,其所需要的内存空间在编译期间完成分配

在这里,当线程请求的内存大于虚拟机所允许的内存,或者当Java虚拟机栈进行动态扩展时申请不到足够的内存时,都会抛出异常

3.本地方法栈

本地方法栈与Java虚拟机栈的区别在于前者为本地方法(native)服务,后者为Java方法(即字节码)服务

HotSpot虚拟机将本地方法栈与Java虚拟机栈合二为一

4.Java堆(Heap)

Java堆是虚拟机管理的内存中最大的部分,它是被所有线程共享的,其目的是为了存放对象实例

Java堆是垃圾收集器管理的内存区域

Java堆可以处于物理上不连续的内存空间中,但在逻辑上被视为连续的

5.方法区

方法区也是线程共享的,它用于储存已经被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据

6.运行时常量池

运行时常量池是方法区的一部分,Class文件中的常量池表将在类加载后存放到这里

常量不一定只有在编译器产生,运行时常量池具有动态性

7.直接内存

直接内存是堆外内存,并不是虚拟机运行时数据区的一部分

HotSpot虚拟机对象揭秘

1.对象的创建

(1)类加载检查
(2)分配内存
(3)初始化内存空间
(4)对对象进行必要设置
(5)执行()方法

2.对象的内存布局

分为三个部分:对象头、实例数据、对齐填充
(1)对象头包括:一,用于储存对象自身的运行时数据,如HashCode,线程持有的锁;二,类型指针,即对象指向它的类型元数据的指针,Java虚拟机通过这个指针来确定该对象是哪个类的实例
(2)实例数据:存储对象真正的有效信息
(3)对齐填充:HotSpot要求对象起始地址必须是8字节的整数倍

3.对象的访问定位

两种访问方式:使用句柄和直接指针
(1)使用句柄:Java堆中可能会划出一块内存作为句柄池,reference指向句柄地址,好处是对象移动时reference不变
(2)直接指针:reference指向对象,好处是减少一次指针定位,速度更快

内存溢出异常

Java堆溢出:OutOfMemoryError异常

Java虚拟机栈和本地方法栈溢出:
1)线程请求的栈深度大于虚拟机所允许的最大深度:StackOverflowError异常
2)虚拟机栈动态扩展时无法申请到足够内存:
OutOfMemoryError异常

方法区和运行时常量池溢出:OutOfMemoryError异常

直接内存溢出:OutOfMemoryError异常

《深入理解Java虚拟机》https://blog.csdn.net/fanxing1964/article/details/79349824

你可能感兴趣的:(Java内存区域与内存溢出异常)