内存充裕下的OOM (一) 令人惊叹的rootcause

/*

  • @author: ahuaxuan
  • @date: 2010-4-30
  • /

在内存充裕的情况下的OOM

理解本文的前提是理解JVM的内存模型:包括

perm, old, young(eden, from(s0), to(s1)), 然后理解young中的垃圾搜集算法(拷贝算法,尤其是eden, from(s0), to(s1)它们分别扮演什么样的角色,为什么任意时间中from和to中必须要有一个是空的), old里的垃圾搜索算法(常见的有:标记压缩算法).

正文:

最近一台测试服务器抛出了OOM的错误,本着不放过一切问题的原则,ahuaxuan把这个OOM研究了一番,最后得出了令人意想不到的结论.

charpter 1, 现象

看到这个OOM的信息之后,ahuaxuan的第一反应是,内存是否真的不够用了,于是使用jmap查看了一下内存的情况,如下:

我们的测试服务器给JVM进程分配的空间是4G,但是从上图中,我们可以看出内存并没有完全用完,尤其是From和TO这两个suvivor空间居然还有900M的空间剩余. Eden 也有112M的空间剩余,Old有288M的空间剩余.

这个不像是空间不足的情况.除非我们的对象真的有这么大,大到超过288M,不管eden还是old都放不下.一个对象要超过300M,那这是一个什么样的对象呀,初步分析,这个对象应该是一个byte数组或者char数组.

charpter2 大对象来源

为了追到这个问题,接下来就是把heap的dump信息拿出来,通过jmap -dump:format=b,file=heap.bin <pid> 把当时的这个进程的dump拿了下来(2.7G).

然后用MAT打开一看.

内存基本被byte和char霸占了.寻找这些byte和char的root.得到

嘿,好家伙,360M的对象,还不在少数(还有其他的图,包含了其他的大对象,就不列出了,主角就是上面的char[]), 而且这些对象是由Lucene创建的,经查,lucene会将索引中的field装载入内存,看似也是合理的,但是不合理的地方是它出现在了RAMInputStream这个类中,因为按照jackrabbit的逻辑(ahuaxuan曾经写过17篇文章来阐述jackrabbit中的搜索模块,详情查看:http://ahuaxuan.iteye.com/category/65829).这里ahuaxuan稍微阐述一下jackrabbit的搜索模块中是怎么使用RAMDirectory的:

新的索引请求到达索引模块,建索引完成之后,jackrabbit不会立即将索引数据刷入磁盘, 而是放在内存中,然后当内存中的数据满足一定量之后(可以在配置文件中设置),这批数据会被一起刷到磁盘中,也就是从RAMDirectory中刷到FSDirectory中,而刚才讲到满足一定的量,其实默认值是100, 也就是说RAMDirectory中最多保持了100个Document.

问题就在这里,100个Document能有360M的field?

这个可能性微乎其微. 如果不是这360M的量有问题,那么就是这100个Document的数量有问题,也许根本就超过了100个.

回过头来我们再来看看上面的逻辑:

1.为每个建立索引数据,存放在内存中

2.如果内存中document满100,刷入磁盘

3.删除内存中的document.

试想,在这个流程中,如果第二步出错.会导致什么情况? 内存中的索引数据不能输入到磁盘上,然后内存中的数据也不能删除(因为代码执行不到下面),所以内存中的数据越来越多,也就是RAMDirectory的数据越来越多.在索引数据不停的增加的过程中,char[]也在越来越大,由于char[]是不能扩容的,所以每次扩容必须新建更大的char[],然后把老的char[]中的数据copy过去,那么问题就是,要建一个比360M的char[]还大的char[]谈何容易? 因为我们的eden只有100M, old只有288M了, 于是OOM应运而生.

charpter 3 验证

查看服务器索引目录,发现确实索引目录的空间的使用率已经到达100%, 于是接着想查看日志文件,想找出IOException之类的异常,可惜的是QA已经将前一天的日志删除,现在的日志所有都是OOM的错误.真是死无对证,这个是比较遗憾的地方.

于是重启服务器,但是并不清空索引目录,不一会,程序又开始出错,打开dump,发现又是类似的问题,RAMDirectory的量还在增加,但是还没有到OOM的阶段(查看RAMDirectory中document的量,已经达到8000多个).

再次验证大对象的问题,写代码创建30m的对象,得到的内存图如下:

当eden不够的时候(共80M,但是已经使用了57M,而我们的新对象是30M),对象没有经过so(from)和s1(to)而直接进入了Old.如果old已经是286M,那么Old也放不下这个对象了,JVM直接抛出了OOM(该例子的系统平台是Mac os 10.5)

charpter 4 处理

将索引目录清空,重启服务器,重新查看dump文件,一切正常,于是跟QA约定保留5天之内的日志数据.从这个一点可以初步确定,OOM产生的原因就是因为磁盘空间不足,导致:

ahuaxuan 写道

1.为每个建立索引数据,存放在内存中
2.如果内存中document满100,刷入磁盘
3.删除内存中的document.

这个流程不能完成,结果就是内存中的数据悦来越多. 最终在为char[n]申请char[m](m >> n)的时候的产生了OOM

charpter 5 延伸

1.为何from space 和to space都达到了450M, 因为它的理论值应该是8:1:1,也就是如果young区有1G, 那么eden应该是800M, from和to都是100M. 也就是说jvm会动态的调整from 和to的值,这个应该也和大对象相关,比如说我们有300m大对象在young区,这个时候要执行copy算法,那么对象需要进入from或者to区,但是from 或者to的容量并不足以容纳这个对象,那么jvm可能会就会调整from和to的大小.以执行拷贝算法.

2.我们可以让生命周期较长的大对象直接进入old而无须进入young么.因为这些对象在young区会经过多次拷贝,然后才能进入Old,有时候并无必要.我们可以通过以下参数来设定:

XX:PretenureSizeThreshold=<byte size>:

写道

• There is a flag (available in 1.4.2 and later) l-XX:PretenureSizeThreshold=<byte size> that can
be set to limit the size of allocations in the young generation. Any allocation larger than this will
not be attempted in the young generation and so will be allocated out of the old generation.
• Objects are now directly created in the older generation if the size of the young generation is
small, and the size of objects are big. The option -XX:PretenureSizeThreshold=<byte size> in the
concurrent collector that can be enabled to indicate the threshold for direct creation in the
older generation. This could effectively be used for creation of caches, lookup tables, etc. which
are long lived and do not have to go through a promotion cycle of being created in the younger
generation and then being copied to the older generation. Use this option with care, since it can
degrade performance instead of improving it. The default value is 0 i.e., no objects are created
directly in the older generation.
• If an allocation fails in the young generation and the object is a large array that does not
contain any references to objects, it can be allocated directly into the old generation. In some
select instances, this strategy was intended to avoid a collection of the young generation by
allocating from the old generation.

如果不设置这个参数,那么不管多大的对象都会在在young 区申请空间,如果设置了这个参数,那么超过规定的大小,这个对象就会直接在old区生成. 但是需要注意的是,如果你的大对象生命周期很短,那么让他们进入old区的必要性也不是很大.

3.关于大的char数组扩容,ahuaxuan这里还有一个例子,是关于char数组的,详情请见

http://ahuaxuan.iteye.com/blog/669440.

to be continue

时间: 2024-10-02 00:59:57

内存充裕下的OOM (一) 令人惊叹的rootcause的相关文章

内存充裕下的OOM (二), StringBuilder和均摊分析

/* *author: ahuaxuan *date: 2010-05-14 */ 介绍: 在前面的一篇文章中http://ahuaxuan.iteye.com/blog/662629, ahuaxuan遇到了一个在内存相对充裕的情况下发生OOM的场景,具体的文章见: 然后时隔不久,该问题再次出现,但是出现在不同的场景下,现象有非常雷同之处.但是这次更离谱: 在某个他人的项目中, eden区还有300m空间的时候发生了OOM. 而在前面一篇文章中,ahuaxuan揭示了在jackrabbit原有

Photoshop CS5笔刷制作令人惊叹的彩色文本

在这个快速教程中,大家会学到如何在Photoshop CS5 中混合不同的形状.笔刷以及混合模式来创建令人惊叹的彩色文本效果.分层PSD文件也包括在内.让我们开始吧! 原文来自:www.adobetutorialz.com 最终图像预览 首先在Adobe Photoshop里创建一个新文件(Ctrl + N),尺寸1900*1200像素(RGB颜色模式),72 pixels/inch..从图层面板底部点击添加图层风格图标,选择渐变叠加. 点击颜色条打开渐变编辑器并按下图设置颜色.点击OK关闭渐变

20个令人惊叹的桌面Docker容器

大家好,今天我们会列出一些运行在Docker容器中的很棒的桌面软件,我们可以在自己的桌面系统中运行它们.Docker 是一个开源项目,提供了一个可以打包.装载和运行任何应用的轻量级容器的开放平台.它没有语言支持.框架和打包系统的限制,从小型的家用电脑到高端服务器,在何时何地都可以运行.它可以使部署和扩展web应用程序.数据库和后端服务像搭积木一样容易,而不依赖特定技术栈或提供商.它主要是由开发.运维工程师使用的,因为它简单.快速和方便,可以用来测试和辅助开发他们产品,但是我们也可以在桌面环境使用

android程序数据保存在单例模式中,保存在内存中,会oom吗

问题描述 android程序数据保存在单例模式中,保存在内存中,会oom吗 ```package com.amt.appstore.cache; import java.util.ArrayList; import java.util.List; import android.content.pm.PackageInfo; import com.amt.appstore.download.DownItem; import com.amt.appstore.model.AboutFirm; imp

Android编程之内存溢出解决方案(OOM)实例总结_Android

本文实例总结了Android编程之内存溢出解决方案(OOM).分享给大家供大家参考,具体如下: 在最近做的工程中发现加载的图片太多或图片过大时经常出现OOM问题,找网上资料也提供了很多方法,但自己感觉有点乱,特此,今天在不同型号的三款安卓手机上做了测试,因为有效果也有结果,今天小马就做个详细的总结,以供朋友们共同交流学习,也供自己以后在解决OOM问题上有所提高,提前讲下,片幅有点长,涉及的东西太多,大家耐心看,肯定有收获的,里面的很多东西小马也是学习参考网络资料使用的,先来简单讲下下: 一般我们

Android编程之内存溢出解决方案(OOM)实例总结

本文实例总结了Android编程之内存溢出解决方案(OOM).分享给大家供大家参考,具体如下: 在最近做的工程中发现加载的图片太多或图片过大时经常出现OOM问题,找网上资料也提供了很多方法,但自己感觉有点乱,特此,今天在不同型号的三款安卓手机上做了测试,因为有效果也有结果,今天小马就做个详细的总结,以供朋友们共同交流学习,也供自己以后在解决OOM问题上有所提高,提前讲下,片幅有点长,涉及的东西太多,大家耐心看,肯定有收获的,里面的很多东西小马也是学习参考网络资料使用的,先来简单讲下下: 一般我们

6 个迷人而令人惊叹的 HTML5 动画特效

HTML5正在快速的进入WEB世界,它在给浏览器各种压力的同时,也带给了我们很多之前意想不到的网页效果,如果我们在网页上能适当的使用一些HTML5元素,可能会给网站带来不一样的用户体验.但是,对于HTML5,现在的浏览器还有很多地方需要改进,比如渲染速度和3D的支持.下面推荐几款非常迷人的HTML5动画特效供大家欣赏和学习. 1.HTML5鼠标滑过图片特效 这个HTML5动画特效可以用在相册中,让用户鼠标滑过后预览相片,效果很不错. 在线演示 / 源码下载 2.基于HTML5 Webkit的落叶

photoshop令人惊叹的人体液态效果后期分享

给各位photoshop软件的使用者们来详细的分享一下令人惊叹的人体液态效果后期. 分享一览:                         好了,以上的信息就是小编给各位photoshop的这一款软件的使用者们带来的详细的令人惊叹的人体液态效果后期分享的全部内容了,希望小编上面分享的内容能够给大家的photoshop学习之路带去新的视觉效果.

20张效果令人惊叹的Apple Store照片欣赏

对于果粉来说,AppleStore一定不陌生.苹果零售店的建筑风格非常统一,使用巨型玻璃作为主体,内部摆着一排排的简洁木质桌子,你可以在这里体验各种苹果产品.毫无疑问,AppleStore已经成为世界上最成功连锁零售店.对于消费者来说,独特的建筑设计和材料已经成为AppleStore的代名词,下面让我们一起欣赏20张效果令人惊叹的AppleStore照片.苹果的吸引力不仅在于它的产品,同时它的AppleStore也是其代表作.我们现在所欣赏的这些设计图,不仅可以给我们一种新的感受,同时我们也相信