3.java.lang.OutOfMemoryError-7种情况实战

一、第一种情况:java.lang.OutOfMemoryError: Java heap space

image.png

使用vistualVM分析堆快照如图,可以看到导致OOM的线程是哪一个,类实例所占用的内存的比例也可以看到

image.png
image.png

点击到OOMObj里边可以看到下边的,垃圾回收的根节点是ArrayList

image.png

二、第二种情况:java.lang.StackOverflowError虚拟机栈溢出,最大深度问题

image.png

三、第三种情况:java.lang.OutOfMemoryError:PermGen space

希望测试:永久代出现内存溢出,PermGen space,大家看 我把对应的永久代的参数设置为5M,单元测试使用的是String的intern方法,如下:

image.png

结果1:GC overhead limit exceed情况如下

image.png

并不是我们想要的异常GC overhead limt exceed检查是Hotspot VM 1.6定义的一个策略,通过统计GC时间来预测是否要OOM了,提前抛出异常,防止OOM发生。Sun 官方对此的定义是:“并行/并发回收器在GC回收时间过长时会抛出OutOfMemroyError。过长的定义是,超过98%的时间用来做GC并且回收了不到2%的堆内存。用来避免内存过小造成应用不能正常工作。“通过日志可以看到old区占用过多导致频繁Full GC,最终导致GC overhead limit exceed。

新增-XX:-UseGCOverheadLimit经过调整后参数如下:

image.png

结果2:

看一下运行效果,是不是很意外,居然报的是java heap space,还不是我们想要的,堆内存溢出
image.png

笔者采用的jdk是1.8,从官方更新看,java8的时候去除PermGen,将其中的方法区移到non-heap中的Metaspace,那是不是意味着原来存储在PermGen的常量会存储在Metaspace,但是从GC日志看Metaspace的大小几乎没有变化,那到底是怎么回事呢?难道String的intern方法不起作用了?原来是在jdk1.6中intern()会将首次遇到的字符串复制到永久代中,返回的是永久代实例的引用,而1.7不在复制实例,只是在常量池中记录首次出现的实例引用,所以会看到Metaspace大小几乎没有变化。

image.png

下边例子说明,第一个str1.intern之后返回的实例对象和在java堆中的str1对象比较为true能够说明这一情况,

str2却出现不同的情况,是因为”java”这个字符串太特别了,在执行本次单元测试之前在某一个地方出现过.(具体是哪里笔者并没有探究)

image.png

接下来我们就制造一下真实方法区内存溢出:java.lang.OutOfMemoryError: Metaspace

单元测试借助CGLIb动态代理生成大量的class载入内存,如下:

image.png

结果3:

image.png

可以看到由于我们创建的类在方法区没有被回收,导致Metaspace被撑爆了。
解决运行时OutOfMemoryError,首先你需要检查是否允许GC从PermGen卸载类,JVM的标准配置相当保守,只要类一创建,即使已经没有实例引用它们,其仍将保留在内存中,特别是当应用程序需要动态创建大量的类但其生命周期并不长时,允许JVM卸载类对应用大有助益,你可以通过在启动脚本中添加以下配置参数来实现:
-XX:+CMSClassUnloadingEnabled默认情况下,这个配置是未启用的,如果你启用它,GC将扫描PermGen区并清理已经不再使用的类。但请注意,这个配置只在UseConcMarkSweepGC的情况下生效,如果你使用其他GC算法,比如:ParallelGC或者Serial GC时,这个配置无效。所以使用以上配置时,请配合:-XX:+UseConcMarkSweepGC如果你已经确保JVM可以卸载类,但是仍然出现内存溢出问题,那么你应该继续分析dump文件,当你拿到生成的堆转储文件,并利用像Eclipse Memory Analyzer Toolkit这样的工具来寻找应该卸载却没被卸载的类加载器,然后对该类加载器加载的类进行排查,找到可疑对象,分析使用或者生成这些类的代码,查找产生问题的根源并解决它。(摘自:https://www.jianshu.com/p/2fdee831ed03?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

四、第四种情况:本机直接内存溢出

image.png

五、java.lang.OutOfMemoryError: unable to create new native thread

会有2种情况:

1. 系统内存耗尽,无法为新线程分配内存(笔者内存16G,无论如何设置Xss也不能测出效果)

2. 创建线程数超过了操作系统的限制,笔者mac,如图

image.png

测试情况:

image.png

插播一下JVM分代划分相关的变化:

(1)附一张图说明jvm内存划分:

image.jpeg

(2)字符串常量池的变化:在java7的时候将字符串常量池则移到java heap,字符串常量池被限制在整个应用的堆内存中,在运行时调用String.intern()增加字符串常量不会使永久代OOM了

(3)方法区的变化:java8的时候去除PermGen,将其中的方法区移到non-heap中的Metaspace,Metaspace与PermGen之间最大的区别在于:Metaspace并不在虚拟机中,而是使用本地内存。如果没有使用-XX:MaxMetaspaceSize来设置类的元数据的大小,其最大可利用空间是整个系统内存的可用空间。JVM也可以增加本地内存空间来满足类元数据信息的存储。但是如果没有设置最大值,则可能存在bug导致Metaspace的空间在不停的扩展,会导致机器的内存不足;进而可能出现swap内存被耗尽;最终导致进程直接被系统直接kill掉。如果类元数据的空间占用达到MaxMetaspaceSize设置的值,将会触发对象和类加载器的垃圾回收,在内存分配失败后会抛出:java.lang.OutOfMemoryError: Metaspace space

六、java.lang.OutOfMemoryError:Out of swap space
Java应用程序在启动时会指定所需要的内存大小,可以通过-Xmx和其他类似的启动参数来指定。在JVM请求的总内存大于可用物理内存的情况下,操作系统会将内存中的数据交换到磁盘上去。当应用程序向JVM native heap请求分配内存失败并且native heap也即将耗尽时,JVM会抛出Out of swap space错误。该错误消息中包含分配失败的大小(以字节为单位)和请求失败的原因。(Native Heap Memory是JVM内部使用的Memory,这部分的Memory可以通过JDK提供的JNI的方式去访问,这部分Memory效率很高,但是管理需要自己去做,如果没有把握最好不要使用,以防出现内存泄露问题。JVM 使用Native Heap Memory用来优化代码载入(JTI代码生成),临时对象空间申请,以及JVM内部的一些操作。)
java.lang.OutOfMemoryError:Out of swap space?往往是由操作系统级别的问题引起的,例如:
1.操作系统配置的交换空间不足。
2.系统上的另一个进程消耗所有内存资源。
3.还有可能是本地内存泄漏导致应用程序失败,比如:应用程序调用了native code连续分配内存,但却没有被释放。
解决方案:
升级机器以包含更多内存
优化应用程序以减少其内存占用

七、Out of memory:Kill process or sacrifice child
为了理解这个错误,我们需要补充一点操作系统的基础知识。操作系统是建立在进程的概念之上,这些进程在内核中作业,其中有一个非常特殊的进程,名叫“内存杀手(Out of memory killer)”。当内核检测到系统内存不足时,OOM killer被激活,然后选择一个进程杀掉。哪一个进程这么倒霉呢?选择的算法和想法都很朴实:谁占用内存最多,谁就被干掉。如果你对OOM Killer感兴趣的话,建议你阅读参考资料2中的文章。
解决方案
解决这个问题最有效也是最直接的方法就是升级内存,其他方法诸如:调整OOM Killer配置、水平扩展应用,将内存的负载分摊到若干小实例上..... 我们不建议的做法是增加交换空间,具体原因已经在前文说过。参考资料②中详细的介绍了怎样微调OOM Killer配置以及OOM Killer选择进程算法的实现,建议你参考阅读。

① 想要了解更多PermGen与Metaspace的内容推荐你阅读:

② 如果你对OOM Killer感兴趣的话,强烈建议你阅读这篇文章:

作者:CHEN川
链接:https://www.jianshu.com/p/2fdee831ed03
來源:简书

doc

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容