第二章 java内存区域与内存溢出异常 《深入理解java虚拟机》

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/xuchuanliang11/article/details/102459280

jvm内存模型

java虚拟机在运行时会把java内存分成不同的数据区域,用户管理不同的数据,如下图:

备注:执行引擎包含java解释器和JIT编译器,关于java解释器、java编译器、JIT编译器的作用简单描述就是java编译器将java源代码编译成字节码(介于源代码和机器代码之间的语言,十六进制);java虚拟机通过解释器将字节码一行行解释执行,实现了java跨平台的特点;存在经常被访问的字节码时,jvm会将热点字节码优化编译成机器码存储在内存中,就能够直接执行,而不需要一行行解释执行,提升jvm运行效率,详情参见另一篇博客https://blog.csdn.net/xuchuanliang11/article/details/101519908

主要分为程序计数器、虚拟机栈、本地方法栈、方法区、堆,下面是对各个数据区域的详细介绍:

程序计数器:是一小块线程私有的内存区域,主要作用是通过改变程序计数器的值来选取下一条需要执行的指令地址,是当前线程执行的字节码行号指示器。

java虚拟机栈:是一块线程私有的内存区域,与线程的生命周期相同,虚拟机栈描述的是java方法执行的内存模型。每个方法在执行的时候,都会创建一个栈帧,用于存储局部变量表(包含基本类型,对象引用,returnAddress类型)、操作数栈、动态链接、方法出口等信息。每个方法从调用到执行完成,对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。当线程请求的栈深度超过虚拟机允许的最大栈深度时,会发生OutOfMemoryError异常。

本地方法栈:基本与java虚拟机栈相同,只不过java虚拟机栈是为执行java方法服务,虚拟机栈是为执行native方法服务。

方法区:是一块线程共享的内存区域,也被称为永久代,主要存储加载的类信息、常量、静态变量、即时编译(JIT)后的代码。

堆:是一块线程共享的内存区域,存放系统中所有的对象实例,可以细分成新生代、老年代;或者Eden区域、from Survivor区域,to Survivor等。一般情况下空间占比是8:1:1,通过-Xms,-Xmn来控制堆内存的大小。之所以分成一个Eden区域和两个Survivor区域的原因参见博客:https://blog.csdn.net/xuchuanliang11/article/details/100978439

直接内存:java引入NIO后,可以直接通过native分配java虚拟机管理的内存之外的内存,提升运行效率,通过在在java堆中的DirectByteBuffer引用外部直接内存,会发生比较难以处理的OutOfMemoryError,详情参见另一篇博客:https://blog.csdn.net/xuchuanliang11/article/details/101018060

对象的创建和访问

对象的创建:当jvm遇到new指令时,先到方法区中查询class是否已经被加载,如果没有被加载则会执行类加载流程;

在hotspot虚拟机中对象在内存中的存储布局分为3块区域:对象头、实例数据、对齐填充

对象的访问:java程序通过栈上的reference来操作堆上的对象,现在版本虚拟机定位方式分为:句柄和直接指针访问两种

句柄:java堆中划分一块内存区域作为句柄池,reference中存放对象的句柄地址,句柄中包含对象的实例数据和类型数据的具体地址信息,如图:

直接指针访问:栈上reference存放的是对象的地址,如图:

句柄优势:对象位置被移动,只需要改动句柄池中句柄指向的地址,不需要改变栈中reference的值;

直接指针访问优势:访问速度快,节省了一次指针定位的时间;

命令:-Xms20m:设置java堆内存最小为20m,-Xmx20m:设置最大堆内存为20M,-XX:+HeapDumpOnOutOfMemoryError:在虚拟机产生OutOfMemoryError时Dump出当前内存堆转储快照

猜你喜欢

转载自blog.csdn.net/xuchuanliang11/article/details/102459280