JVM内存区域和内存溢出异常

运行时数据区:
在这里插入图片描述**1、程序计数器:**内存空间小,线程私有。字节码解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成。如果线程正在执行一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 方法,这个计数器的值则为 (Undefined)。此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。
简述:程序计数器用来记录执行到哪了。
**2、Java虚拟机栈:**线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。局部变量表:存放了编译期可知的各种基本类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型)和 returnAddress 类型(指向了一条字节码指令的地址)
StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度。
OutOfMemoryError:如果虚拟机栈可以动态扩展,而扩展时无法申请到足够的内存。
简述:存放局部变量、操作数栈、动态链接、方法出口等信息。当栈深度过深时,StackOverflowError;当虚拟机栈动态扩展,无法申请足够内存时,OutOfMemoryError。
**3、本地方法栈:**区别于 Java 虚拟机栈的是,Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。也会有 StackOverflowError 和 OutOfMemoryError 异常。
简述:用于执行Native方法,也有StackOverflowError 和 OutOfMemoryError 异常。
**4、Java堆:**对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。内部会划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。OutOfMemoryError:如果堆中没有内存完成实例分配,并且堆也无法再扩展时,抛出该异常。
简述:存放对象和数组,线程共享。有新生代和老生代。会出现OutOfMemoryError。
**5、方法区:**属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
简述:线程共享。类信息、常量、静态变量、即时编译器编译后的代码。
**6、运行时常量池:**方法区的一部分。用于存放编译期生成的各种字面量和符号引用。编译器和运行期(String 的 intern() )都可以将常量放入池中。内存有限,无法申请时抛出 OutOfMemoryError。
简述:方法区的一部分,存放编译期生成的各种字面量和符号引用。如字符串常量池。
**7、直接内存:**不是虚拟机运行时数据区的部分。在 JDK 1.4 中新加入 NIO (New Input/Output) 类,引入了一种基于通道(Channel)和缓存(Buffer)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。可以避免在 Java 堆和 Native 堆中来回的数据耗时操作。
OutOfMemoryError:会受到本机内存限制,如果内存区域总和大于物理内存限制从而导致动态扩展时出现该异常
简述:只是一起讲。属于堆外内存。不受Java堆大小限制。受本机内存限制,所以还是会OutOfMemoryError异常。

HotSpot 虚拟机对象探秘:
主要介绍数据是如何创建、如何布局以及如何访问的。
1、对象的创建:
遇到一条new指令时,检查这个指令能否在常量池中定位到一个类的符号,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,执行相应的类加载过程。
接下来给新生对象分配内存。在Java堆中划出确定大小的一块内存。
如何保证并发情况下的划分内存的线程安全,两个解决方案:同步处理,即CAS配上失败重试;Java堆预先准备本地缓冲区(TLAB),哪个线程要分配内存,就在哪个线程的TLAB上分配。
将分配到的内存空间都初始化为零值(即int类型默认为0)。
堆对象进行必要的设置,例如对象是哪个类的实例,如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。
从虚拟机视角,一个新对象已经产生。从Java程序来看,对象才刚刚开始(方法还没执行,所有字段都还是零值)。
2、对象的内存布局:
1)数据头:对象自身的运行时数据(固定32bit或64bit,哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等)+类型指针,来确定对象是哪个类的实例。
2)实例数据:各种类型的字段内容(包含父类继承下来的和子类中定义的)。
3)填充信息:不一定会有,保证对象必须是8字节的整数倍。
3、对象的访问定位:
两种方式:句柄和直接指针。
句柄:reference保存句柄,句柄保存对象实例数据与类型数据各自的具体地址信息。
直接指针访问:reference存储的就是对象地址
在这里插入图片描述在这里插入图片描述实战:OutOfMemoryError异常:
除了程序计数器,都有可能出现OutOfMemoryError异常。
1、java堆溢出
2、虚拟机栈和本地方法栈溢出
3、方法区和运行时常量溢出
4、本机直接内存溢出

发布了148 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_33321609/article/details/104640445