第25讲 | 谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?
该思维导图由 AI 生成,仅供参考
典型回答
- 深入了解
- 翻译
- 解释
- 总结
JVM内存区域划分及OutOfMemoryError问题是Java虚拟机内存管理的重要话题。文章介绍了程序计数器、Java虚拟机栈、堆、方法区、运行时常量池和本地方法栈等JVM内存结构,强调了堆是核心区域,方法区存储元数据,运行时常量池是方法区的一部分,本地方法栈支持本地方法调用。文章还提到可能导致OutOfMemoryError的情况,如堆内存溢出、方法区溢出等,并指出不同厂商的JVM实现可能存在差异。此外,文章还介绍了直接内存区域和JVM本身所需的内存,以及不同内存区域可能发生的OutOfMemoryError情况。总的来说,本文深入浅出地介绍了JVM内存区域划分和可能发生的内存异常情况,对于想要深入了解Java虚拟机内存管理的读者具有很高的参考价值。
《Java 核心技术面试精讲》,新⼈⾸单¥59
全部留言(64)
- 最新
- 精选
- I am a psycho如果仅从jvm的角度来看,要看下新生代和老年代的垃圾回收机制是什么。如果新生代是serial,会默认使用copying算法,利用两块eden和survivor来进行处理。但是默认当遇到超大对象时,会直接将超大对象放置到老年代中,而不用走正常对象的存活次数记录。因为要放置的是一个byte数组,那么必然需要申请连续的空间,当空间不足时,会进行gc操作。这里又需要看老年代的gc机制是哪一种。如果是serial old,那么会采用mark compat,会进行整理,从而整理出连续空间,如果还不够,说明是老年代的空间不够,所谓的堆内存大于100m是新+老共同的结果。如果采用的是cms(concurrent mark sweep),那么只会标记清理,并不会压缩,所以内存会碎片化,同时可能出现浮游垃圾。如果是cms的话,即使老年代的空间大于100m,也会出现没有连续的空间供该对象使用。
作者回复: 非常不错的总结
2018-07-033305 - Len从不同的垃圾收集器角度来看: 首先,数组的分配是需要连续的内存空间的(据说,有个别非主流JVM支持大数组用不连续的内存空间分配🤔)。所以: 1)对于使用年轻代和老年代来管理内存的垃圾收集器,堆大于 100M,表示的是新生代和老年代加起来总和大于100M,而新生代和老年代各自并没有大于 100M 的连续内存空间。 进一步,又由于大数组一般直接进入老年代(会跳过对对象的年龄的判断),所以,是否可以认为老年代中没有连续大于 100M 的空间呢。 2)对于 G1 这种按 region 来管理内存的垃圾收集器,可能的情况是没有多个连续的 region,它们的内存总和大于 100M。 当然,不管是哪种垃圾收集器以及收集算法,当内存空间不足时,都会触发 GC,只不过,可能 GC 之后,还是没有连续大于 100M 的内存空间,于是 OOM了。
作者回复: 很好的视角,g1 region之类确实有影响,另外g1还是有年代的概念的
2018-07-0344 - 夏洛克的救赎Tomcat运行中突然出现java.lang.OutOfMemoryError: PermGen space有什么工具可以排查原因吗?
作者回复: 简单点处理,可以: 先看看永久带给了多大,如果太小,可以适当增大,使用'-XX:MaxPermSize=NNNm'; 如果没开启classunloading,可以根据GC选项做配置,例如,如果使用的CMS,可以加上“-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled” 通常就能解决问题了,如果还是有问题,那就要看看是不是出现了classloader leak,常见做法如,取Heap dump,然后用类似Eclipse MAT这样的工具,看看有没有不回收的自定义classloader实例之类
2019-01-1420 - 任鹏斌老师既然元数据区也存在溢出,那么为什么要用元数据区替换永久代呢,有什么好处吗?
作者回复: metaspace 默认是自增的,永久带做不到
2018-08-0617 - markin老师,能否跟我们介绍一下您平时获取资料的渠道。比如apache的一些开源项目,官网上就有很丰富的文档。但是我们获取jvm相关文档的渠道少之又少,无非就是博客或者书籍,这些都比较繁杂,并且可能参杂着很多难以识别的错误观点。授人以鱼不如授人以渔,先谢谢老师了。
作者回复: Oracle官网也提供了很多好的文档: 虚拟机规范 https://docs.oracle.com/javase/specs/jvms/se8/html/index.html 诊断指南 https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/index.html 调优指南 https://docs.oracle.com/javase/10/gctuning/ Openjdk网站,或者那些感兴趣的邮件列表 http://mail.openjdk.java.net/mailman/listinfo YouTube上查查javaone, JVM summit之类 回头有必要整理个书单之类 但这些东西太多了,自己把握一下
2018-07-0817 - 爱吃芒果的董先森因为给数组分配的是连续地址,而显示的是总的地址,不管是不是连续的。
作者回复: 也对,最好综合考虑堆内存结构、gc区别等,后续会讲解
2018-07-0311 - 鹅米豆发可能一,新生代没有足够的连续空间,且不能直接在老年代分配。比如E+S0+S1>100MB,但E<100MB,S0<100MB。 可能二,大对象直接进入老年代,但老年代也没有足够的连续空间。参数+XX:PretenureSizeThreshold。 可能三,线程数量太多,导致物理内存不足。 可能四,直接内存使用太多,导致物理内存不足。
作者回复: 不错,下一章会有更多内存结构细节
2018-07-039 - tyson堆内存100M 包含了新生代(eden+s0+1)和老年代,大对象一般分配在老年代,那么最有可能在分配过程中老年代的空间不足。
作者回复: 不错,可能性很多,其实和gc的选择也有关,例如g1 region比较小
2018-07-038 - 代码狂徒老师,您是说方法区就是有永久代?那也就是说方法区在jdk8中已经不存在了?元数据区跟方法区有什么区别呢?那您的图是jdk7的图,有8得图吗?求解
作者回复: 不是,方法区只是个逻辑概念,永久带和元数据区是具体设计、实现的选择; 以前放到永久带,而且永久带内部还有类似intern字符串之类内容; 元数据区具体内容和永久带也有区别,文章介绍了; 那个图只是个简化示例,8去掉永久带就是了,具体到比较复杂的gc比如g1,就不是这个结构,请看后面讲
2018-07-103 - 李二木老师,关于这篇文章留的问题你可以给个你的答案吗?
作者回复: 嗯,参考我的回复,下一讲中有更多细节,具体堆内结构还是会划分,例如tlab,eden等,可以简单理解,对象分配是试图tlab,太大就eden,还不行就oldgen,所以我们需要的是相应区域有连续空闲
2018-07-053