• I am a psycho
    2018-07-03
    如果仅从jvm的角度来看,要看下新生代和老年代的垃圾回收机制是什么。如果新生代是serial,会默认使用copying算法,利用两块eden和survivor来进行处理。但是默认当遇到超大对象时,会直接将超大对象放置到老年代中,而不用走正常对象的存活次数记录。因为要放置的是一个byte数组,那么必然需要申请连续的空间,当空间不足时,会进行gc操作。这里又需要看老年代的gc机制是哪一种。如果是serial old,那么会采用mark compat,会进行整理,从而整理出连续空间,如果还不够,说明是老年代的空间不够,所谓的堆内存大于100m是新+老共同的结果。如果采用的是cms(concurrent mark sweep),那么只会标记清理,并不会压缩,所以内存会碎片化,同时可能出现浮游垃圾。如果是cms的话,即使老年代的空间大于100m,也会出现没有连续的空间供该对象使用。

    作者回复: 非常不错的总结

    
     154
  • 石头狮子
    2018-07-03
    1,新生代大小过小。无法分配足够的内存。同时也老年代过小,导致提升失败。这时系统认为没有足够的空间存放该100M数据。
    2,栈可以抽象的看成计算资源。堆看成存储资源。计算资源不共享,不会发生线程安全问题。堆资源共享,
    容易发生线程安全问题。
    3,JAVA 封装了不同系统的线程模型,结果是在 java 内部有实现了一个通用的 java线程库。所以就需要用户内存来保存线程信息。
    
     16
  • Len
    2018-07-03
    从不同的垃圾收集器角度来看:

    首先,数组的分配是需要连续的内存空间的(据说,有个别非主流JVM支持大数组用不连续的内存空间分配🤔)。所以:

    1)对于使用年轻代和老年代来管理内存的垃圾收集器,堆大于 100M,表示的是新生代和老年代加起来总和大于100M,而新生代和老年代各自并没有大于 100M 的连续内存空间。

    进一步,又由于大数组一般直接进入老年代(会跳过对对象的年龄的判断),所以,是否可以认为老年代中没有连续大于 100M 的空间呢。

    2)对于 G1 这种按 region 来管理内存的垃圾收集器,可能的情况是没有多个连续的 region,它们的内存总和大于 100M。

    当然,不管是哪种垃圾收集器以及收集算法,当内存空间不足时,都会触发 GC,只不过,可能 GC 之后,还是没有连续大于 100M 的内存空间,于是 OOM了。

    展开

    作者回复: 很好的视角,g1 region之类确实有影响,另外g1还是有年代的概念的

    
     14
  • 鸡肉饭饭
    2018-07-03
    我们拿JDK7来说,有可能的原因是JVM的剩余内存有100M,但是它是分在不同年龄代的内存区域。

    因此应当单独的去查看每一块eden,survivor,old的大小,(通过SurvivorRatio知道s和e的比例大小,通过MaxNewSize知道young和old的比例)看看这三块区域是否有超过100M的内存大小。如果没有,就是因为没有一个区域能够再存储一个100M的对象。

    如果有,就可以通过工具查看下,每一块e s o每一块区域剩下的内存空间,如果没有一块内存大小超过100M,便是因为这个原因导致数组分配失败。
    展开
    
     11
  • 爱吃芒果的董先森
    2018-07-03
    因为给数组分配的是连续地址,而显示的是总的地址,不管是不是连续的。

    作者回复: 也对,最好综合考虑堆内存结构、gc区别等,后续会讲解

    
     7
  • 任鹏斌
    2018-08-06
    老师既然元数据区也存在溢出,那么为什么要用元数据区替换永久代呢,有什么好处吗?

    作者回复: metaspace 默认是自增的,永久带做不到

    
     6
  • 夏洛克的救赎
    2019-01-14
    Tomcat运行中突然出现java.lang.OutOfMemoryError: PermGen space有什么工具可以排查原因吗?

    作者回复: 简单点处理,可以:
    先看看永久带给了多大,如果太小,可以适当增大,使用'-XX:MaxPermSize=NNNm';
    如果没开启classunloading,可以根据GC选项做配置,例如,如果使用的CMS,可以加上“-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled”

    通常就能解决问题了,如果还是有问题,那就要看看是不是出现了classloader leak,常见做法如,取Heap dump,然后用类似Eclipse MAT这样的工具,看看有没有不回收的自定义classloader实例之类

    
     5
  • markin
    2018-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之类
    回头有必要整理个书单之类

    但这些东西太多了,自己把握一下

    
     5
  • tyson
    2018-07-03
    堆内存100M 包含了新生代(eden+s0+1)和老年代,大对象一般分配在老年代,那么最有可能在分配过程中老年代的空间不足。

    作者回复: 不错,可能性很多,其实和gc的选择也有关,例如g1 region比较小

    
     5
  • 鹅米豆发
    2018-07-03
    可能一,新生代没有足够的连续空间,且不能直接在老年代分配。比如E+S0+S1>100MB,但E<100MB,S0<100MB。

    可能二,大对象直接进入老年代,但老年代也没有足够的连续空间。参数+XX:PretenureSizeThreshold。

    可能三,线程数量太多,导致物理内存不足。

    可能四,直接内存使用太多,导致物理内存不足。

    作者回复: 不错,下一章会有更多内存结构细节

    
     5
  • 师琳博
    2018-07-03
    100m的byte数组,一个byte对应一个引用,这样需要100m个的引用,所以需要的栈空间也不会低于100m,而对象的引用是在栈中分配的,(栈和堆加起来估计不低于200m)况且还是数组,对应的那么多引用还需要分配连续的内存空间,堆空间够的话,个人认为可能是栈空间不足造成的
    
     2
  • 鲸息
    2019-03-14
    老年代碎片化了。需要查看老年代的内存使用状况,对于 CMS 可以间接地看是否打开了每次 CMS GC 以后就立刻做一次碎片整理的开关。
    
     1
  • 刘p辉
    2018-07-30
    1.首先堆内存是分代的,总的内存超过100M,不能保证新生代,老年代都有足够的内存。
    2.为对象,数组分配内存需要连续的内存空间,有可能堆的总内存远超过要分配内存大小,但是在即使进行过垃圾回收(标记整理)后还是不存在足够的连续内存空间就会OOM。
    
     1
  • Geek_135148
    2018-07-29
    请问compressed class space区域怎么理解?是metasapce的一部分吗?如果是的话,有些采集工具为何会把它占的大小单独显示出来呢?而不直接显示metaspace的大小呢
    
     1
  • 代码狂徒
    2018-07-10
    老师,您是说方法区就是有永久代?那也就是说方法区在jdk8中已经不存在了?元数据区跟方法区有什么区别呢?那您的图是jdk7的图,有8得图吗?求解

    作者回复: 不是,方法区只是个逻辑概念,永久带和元数据区是具体设计、实现的选择;
    以前放到永久带,而且永久带内部还有类似intern字符串之类内容;
    元数据区具体内容和永久带也有区别,文章介绍了;
    那个图只是个简化示例,8去掉永久带就是了,具体到比较复杂的gc比如g1,就不是这个结构,请看后面讲

    
     1
  • Steven⁰⁰⁸
    2018-07-04
    数组是连续分配的,gc表明有多余100m,但有可能满足不了连续100m的空间,故会报OOME
    
     1
  • boom
    2018-07-03
    小白请教一个不相关的问题~java 内存模型跟 jvm内存模型的区别与联系是啥呢~

    作者回复: 怎么叫都有,看上下文,jsr133 jmm是解决多线程环境一致性,或者可以看做memory ordering model

    
     1
  • 三口先生
    2018-07-03
    堆内存比例设置不合理

    作者回复: 也对,回答比较简洁,哈哈

    
     1
  • sunlight001
    2018-07-03
    堆上有空间的划分,新生代和老年代,有可能新生代的空间不够,看到的是老年代的空间,个人猜测😃
    
     1
  • 未完的歌
    2018-07-03
    有可能是内存碎片化问题,或者是大对象的内存分配策略问题。
    需要了解一下积极垃圾收集算法,例如Mark Sweep就会造成内存碎片化问题,另外内存分配策略也是一个关注点。

    作者回复: 是的

    
     1
我们在线,来聊聊吧