jvm学习笔记1--内存区域与内存溢出
-
运行时数据区域组成
1.1 程序计数器
-
当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令。
-
为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,因此属于“线程私有”的内存。
-
执行 java方法,则记录的是虚拟机字节码的地址;如果执行的是 native方法,则值为空( Undefined)
-
异常:唯一一个在 Java虚拟机规范中没有规定任何 OutOfMemoryError情况的区域。
1.2 Java虚拟机栈( java virtual machine stacks)
-
Java虚拟机栈是线程私有的,生命周期与线程相同。
-
栈帧( stack frame):每个方法被执行的时候会创建一个栈帧,存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
-
局部变量表:存放编译器可知的各种基本数据类型、对象引用(根据不同的虚拟机实现,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄)、 returnAddress类型(指向一条字节码指令的地址)。局部变量表的空间在编译期是完全确定的,所以在编译期间完成分配,在运行期间不会再改变大小。
-
异常:
1) 如果线程请求的栈深度大于虚拟机所允许的深度,抛出 StackOverflowError
2) 如果虚拟机栈可以动态扩展,当扩展时无法申请到足够内存,则抛出 OutOfMemoryError异常。
1.3 本地方法栈
1.4 Java堆
1.5 方法区
1) 属于方法区的一部分。
2) 存放内容: Class文件中的常量池(存放编译期生成的各种字面量和符号引用);翻译出来的直接引用;运行期间产生的新的常量(譬如 String类的 intern()方法)
1.6 直接内存:
2. 对象访问
2.1 Object obj = new Object
-
Object obj:作为一个reference类型数据存储在栈帧的本地变量表中;
-
new Object():作为一个Object类型的实例数据存在在java堆中;同时,还必须包含能找到Object类型数据(如对象类型、父类、实现的接口、方法等)的地址信息;
-
Object类型数据(如对象类型、父类、实现的接口、方法等)存储在方法区中;
2.2 两种访问对象的方式:句柄、直接指针
Java堆中会划分出一块内存来作为句柄池;栈帧中存储的reference值就是对象的句柄地址;句柄中包含了对象实例数据和类型数据各自的具体地址信息
优点:对象被移动时,只需要改变句柄中的实例数据指针,而reference本身不需要被修改。
Java堆对象的布局必须考虑如何放置类型数据的相关信息;栈帧中存储的reference值就是对象地址。
优点:速度更快,节省了一次指针定位的时间开销。Sun HotSpot使用该方式。
3. 内存溢出
3.1 Java堆溢出
1)通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转储快照进行分析,确认是内存泄漏还是内存溢出
2) 如果是内存泄漏,则查看泄漏对象到GC Roots的引用链,得知泄漏对象通过怎样的路径与GC Roots相关联导致无法回收。
3)如果是内存溢出(即对象确实都还必须存活着),则检查堆参数(-Xmx与-Xms)与机器物理内存对比看是否可以调大;从代码上检查是否存在某些对象生命周期过长的情况,尝试优化减少程序运行期的内存消耗。
3.2 虚拟机栈溢出
1)StackOverflowError
Exception in thread “main” java.lang.StackOverflowError
说明:单线程情况下,不管是由于栈帧太大,还是由于虚拟机栈容量太小,当内存无法分配的时候,都抛出StackOverflowError
2)OutOfMemoryError
Exception in thread “main” java.lang.OutOfMemoryError:unable to create new native thread
多线程情况下,通过不断地建立线程的方式可以产生该异常,而且,为每个线程的栈分配的内存越大,越容易产生该异常。
1) StackOverflowError
有错误堆栈可以阅读,容易找到问题所在。而且,如果使用虚拟机默认参数,栈深度对于正常的方法调用是完全够用的。
2) OutOfMemoryError
由于虚拟机提供了参数来控制Java堆和方法区这两部分内存的最大值,而程序计数器消耗的内存很小可以忽略掉,因此用本机内存扣除掉这两部分内存后,剩下的内存就由虚拟机栈和本地方法栈瓜分了。所以对于建立多个线程导致的内存溢出,有两个措施解决:
2.1 减少最大堆内存
2.2 减少栈容量(是为了能够创建更多的线程)
3.3 运行时常量池溢出
-
Vm args: -XX:PermSize=10M -XX:MaxPermSize=10M
-
可能原因:运行时产生了大量的新的常量(譬如String类的intern()方法)
-
异常堆栈信息: Exception in thread “main” java.lang.OutOfMemoryError:PermGen space
3.4 方法区溢出
-
Vm args: -XX:PermSize=10M -XX:MaxPermSize=10M
-
可能原因:运行时产生了大量的类,导致在方法区存储了大量的类型数据信息(譬如CGLIB动态生成子类、动态产生JSP、OSGI应用(即使是同一个类文件,不同的classloader也会视为不同的类))
-
异常堆栈信息:Exception in thread “main” java.lang.OutOfMemoryError:PermGen space
3.5 本机直接内存溢出
注:本笔记主要参考:深入理解Java虚拟机--Jvm高级特性与最佳实践一书及网络资料
分享到:
相关推荐
JVM性学习笔记-基本原理,内存模型,JVM参数设置,类加载器原理,JDK自带工具
1.1 对象声明 1.2 相关方法 1.3 系统知识 1.3.1 虚拟内存 1.3.1.1 物理和虚拟寻址 1.3.1.1.1 物理寻址 1.3.1.1.2 虚
程序运行要用到的内存大于虚拟机能提供的最大内存就发生内存溢出了, 内存溢出的问题要看业务和系统大小而定,对于某些系统可能内存溢出不常见,但某些系统还是很常见的解决的方法
jvm性能调优-jvm内存模型和优化-performance-jvm-memorymodel-optimize
JVM调优总结 -Xms -Xmx -Xmn -Xss JVM调优总结 -Xms -Xmx -Xmn -Xss
java jvm 参数 -Xms -Xmx -Xmn -Xss -
jvm内存溢出 学习笔记
JVM学习笔记(一)--------基本结构 JVM学习笔记(二)----java代码编译和执行的整个过程 JVM学习笔记(三)---------内存管理和垃圾回收 JVM学习笔记(四)------内存调优
JVM实战-对象访问与内存溢出异常解析
一份JVM学习的笔记,含查看JVM运行时信息\JVM垃圾收集信息\JVM锁信息等
jvm 调优笔记-jvm
jvm内存反洗工具:
java之jvm学习笔记十一(访问控制器)-源码
主要为大家讲解JVM内存模型|内存结构|内存屏障,他们的概念,有什么关联以及各种的功能
nginx-upstream-jvm-route 支持nginx版本1.15 解决nginx: [emerg] invalid parameter "srun_id=tomcat1" 问题
JVM调优总结 -Xms -Xmx -Xmn -Xss
深入理解JVM内存区域与内存溢出异常
JVM学习笔记.docx
java之jvm学习笔记五(实践写自己的类装载器)