第25讲 | 谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?
第25讲 | 谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?
讲述:黄洲君
时长10:43大小4.90M
典型回答
考点分析
知识扩展
一课一练
赞 22
提建议
精选留言(64)
- I am a psycho2018-07-03如果仅从jvm的角度来看,要看下新生代和老年代的垃圾回收机制是什么。如果新生代是serial,会默认使用copying算法,利用两块eden和survivor来进行处理。但是默认当遇到超大对象时,会直接将超大对象放置到老年代中,而不用走正常对象的存活次数记录。因为要放置的是一个byte数组,那么必然需要申请连续的空间,当空间不足时,会进行gc操作。这里又需要看老年代的gc机制是哪一种。如果是serial old,那么会采用mark compat,会进行整理,从而整理出连续空间,如果还不够,说明是老年代的空间不够,所谓的堆内存大于100m是新+老共同的结果。如果采用的是cms(concurrent mark sweep),那么只会标记清理,并不会压缩,所以内存会碎片化,同时可能出现浮游垃圾。如果是cms的话,即使老年代的空间大于100m,也会出现没有连续的空间供该对象使用。展开
作者回复: 非常不错的总结
共 3 条评论296 - Len2018-07-03从不同的垃圾收集器角度来看: 首先,数组的分配是需要连续的内存空间的(据说,有个别非主流JVM支持大数组用不连续的内存空间分配🤔)。所以: 1)对于使用年轻代和老年代来管理内存的垃圾收集器,堆大于 100M,表示的是新生代和老年代加起来总和大于100M,而新生代和老年代各自并没有大于 100M 的连续内存空间。 进一步,又由于大数组一般直接进入老年代(会跳过对对象的年龄的判断),所以,是否可以认为老年代中没有连续大于 100M 的空间呢。 2)对于 G1 这种按 region 来管理内存的垃圾收集器,可能的情况是没有多个连续的 region,它们的内存总和大于 100M。 当然,不管是哪种垃圾收集器以及收集算法,当内存空间不足时,都会触发 GC,只不过,可能 GC 之后,还是没有连续大于 100M 的内存空间,于是 OOM了。展开
作者回复: 很好的视角,g1 region之类确实有影响,另外g1还是有年代的概念的
39 - 石头狮子2018-07-031,新生代大小过小。无法分配足够的内存。同时也老年代过小,导致提升失败。这时系统认为没有足够的空间存放该100M数据。 2,栈可以抽象的看成计算资源。堆看成存储资源。计算资源不共享,不会发生线程安全问题。堆资源共享, 容易发生线程安全问题。 3,JAVA 封装了不同系统的线程模型,结果是在 java 内部有实现了一个通用的 java线程库。所以就需要用户内存来保存线程信息。展开20
- 夏洛克的救赎2019-01-14Tomcat运行中突然出现java.lang.OutOfMemoryError: PermGen space有什么工具可以排查原因吗?
作者回复: 简单点处理,可以: 先看看永久带给了多大,如果太小,可以适当增大,使用'-XX:MaxPermSize=NNNm'; 如果没开启classunloading,可以根据GC选项做配置,例如,如果使用的CMS,可以加上“-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled” 通常就能解决问题了,如果还是有问题,那就要看看是不是出现了classloader leak,常见做法如,取Heap dump,然后用类似Eclipse MAT这样的工具,看看有没有不回收的自定义classloader实例之类
19 - 任鹏斌2018-08-06老师既然元数据区也存在溢出,那么为什么要用元数据区替换永久代呢,有什么好处吗?
作者回复: metaspace 默认是自增的,永久带做不到
16 - markin2018-07-08老师,能否跟我们介绍一下您平时获取资料的渠道。比如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之类 回头有必要整理个书单之类 但这些东西太多了,自己把握一下
15 - 鸡肉饭饭2018-07-03我们拿JDK7来说,有可能的原因是JVM的剩余内存有100M,但是它是分在不同年龄代的内存区域。 因此应当单独的去查看每一块eden,survivor,old的大小,(通过SurvivorRatio知道s和e的比例大小,通过MaxNewSize知道young和old的比例)看看这三块区域是否有超过100M的内存大小。如果没有,就是因为没有一个区域能够再存储一个100M的对象。 如果有,就可以通过工具查看下,每一块e s o每一块区域剩下的内存空间,如果没有一块内存大小超过100M,便是因为这个原因导致数组分配失败。展开12
- 爱吃芒果的董先森2018-07-03因为给数组分配的是连续地址,而显示的是总的地址,不管是不是连续的。
作者回复: 也对,最好综合考虑堆内存结构、gc区别等,后续会讲解
10 - tyson2018-07-03堆内存100M 包含了新生代(eden+s0+1)和老年代,大对象一般分配在老年代,那么最有可能在分配过程中老年代的空间不足。
作者回复: 不错,可能性很多,其实和gc的选择也有关,例如g1 region比较小
7 - 鹅米豆发2018-07-03可能一,新生代没有足够的连续空间,且不能直接在老年代分配。比如E+S0+S1>100MB,但E<100MB,S0<100MB。 可能二,大对象直接进入老年代,但老年代也没有足够的连续空间。参数+XX:PretenureSizeThreshold。 可能三,线程数量太多,导致物理内存不足。 可能四,直接内存使用太多,导致物理内存不足。展开
作者回复: 不错,下一章会有更多内存结构细节
8 - 代码狂徒2018-07-10老师,您是说方法区就是有永久代?那也就是说方法区在jdk8中已经不存在了?元数据区跟方法区有什么区别呢?那您的图是jdk7的图,有8得图吗?求解
作者回复: 不是,方法区只是个逻辑概念,永久带和元数据区是具体设计、实现的选择; 以前放到永久带,而且永久带内部还有类似intern字符串之类内容; 元数据区具体内容和永久带也有区别,文章介绍了; 那个图只是个简化示例,8去掉永久带就是了,具体到比较复杂的gc比如g1,就不是这个结构,请看后面讲
3 - 李二木2018-07-05老师,关于这篇文章留的问题你可以给个你的答案吗?
作者回复: 嗯,参考我的回复,下一讲中有更多细节,具体堆内结构还是会划分,例如tlab,eden等,可以简单理解,对象分配是试图tlab,太大就eden,还不行就oldgen,所以我们需要的是相应区域有连续空闲
3 - Steven⁰⁰⁸2018-07-04数组是连续分配的,gc表明有多余100m,但有可能满足不了连续100m的空间,故会报OOME2
- 师志强2018-07-03100m的byte数组,一个byte对应一个引用,这样需要100m个的引用,所以需要的栈空间也不会低于100m,而对象的引用是在栈中分配的,(栈和堆加起来估计不低于200m)况且还是数组,对应的那么多引用还需要分配连续的内存空间,堆空间够的话,个人认为可能是栈空间不足造成的共 1 条评论3
- 叫啥不行2019-12-19用的jdk1.8,无论开启还是关闭逃逸分析,使用jmap,对象数量少的时候,堆里面对象数量跟我创建的数量一样。 创建对象多的时候,关闭逃逸分析堆内存对象与创建的一样,但是开启后,堆内对象数量就变得很少了,这个是因为什么,有没有大佬能解答一下,谢谢。共 1 条评论1
- 硅谷居士2019-03-14老年代碎片化了。需要查看老年代的内存使用状况,对于 CMS 可以间接地看是否打开了每次 CMS GC 以后就立刻做一次碎片整理的开关。1
- 江南豆沙包2018-11-15老师,你好。看了文章后查一些资料。都有这段话:元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。 这里说的本地内存是不是和你文中说的直接内存是一个概念?
作者回复: 直接内存一般会指代 direct buffer那部分,看说话的上下文
1 - 刘p辉2018-07-301.首先堆内存是分代的,总的内存超过100M,不能保证新生代,老年代都有足够的内存。 2.为对象,数组分配内存需要连续的内存空间,有可能堆的总内存远超过要分配内存大小,但是在即使进行过垃圾回收(标记整理)后还是不存在足够的连续内存空间就会OOM。1
- Geek_1351482018-07-29请问compressed class space区域怎么理解?是metasapce的一部分吗?如果是的话,有些采集工具为何会把它占的大小单独显示出来呢?而不直接显示metaspace的大小呢1
- 一个坏人2018-07-18老师好,请教一个问题。JMM 模型中 各种内存分区 是逻辑分区的。JVM会根据参数计算每一块分区的起始地址、结束地址?如果会,什么时候执行这一操作呢?每一块区域有规定的顺序么?
作者回复: vm启动或者线程创建就会计算,但不是完全固定值,运行时可调整
2