jvm学习笔记1--内存区域与内存溢出
1.1 程序计数器
1.2 Java虚拟机栈( java virtual machine stacks)
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
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 运行时常量池溢出
3.4 方法区溢出
3.5 本机直接内存溢出
注:本笔记主要参考:深入理解Java虚拟机--Jvm高级特性与最佳实践一书及网络资料