内存不足:杀死进程还是牺牲子进程
2014-07-02 13:55
204 查看
本文转载自 ImportNew,翻译: ImportNew.com - 秋双
原文链接:javacodegeeks,译文链接:http://www.importnew.com/12285.html
早上6点,我不得不开始处理“叫醒”我的一些问题。因为当这些问题发生的时候,我的手机铃声响了。昏睡中的我非常不情愿地拿起了手机,检查我是否疯狂到将叫醒闹钟设在了早上5点。原来是监控系统发现一个Plumbr服务死掉了。
作为一名该领域经验丰富的高手,我首先来到了咖啡机旁。我需要用一杯咖啡开始工作。第一个问题,在应用崩溃之前看起来一切运行正常。日志中没有错误,没有告警,也没有其他任何异常。
我们的监控系统已经察觉到进程死掉了,并且已经重启了崩溃的服务。因为血液中已经有了咖啡因,我开始收集更多的证据。30分钟后,在/var/log/kern.log文件中发现了以下内容:
很显然,我们成了Linux内核的受害者。大家都知道,Linux建立在一些守护进程之上。这些守护进程被几个看起来糟透了的内核任务看管。所有现代Linux内核都内置了一个被称为“内存不足杀手”的机制,它在内存不足的情况下会杀掉用户进程。当检测到内存不足时,杀手会被激活并选择一个进程杀死。选择机制是用启发式算法对所有进程进行打分,最后选择得分最低的进程杀死。
默认情况下,Linux内核允许进程请求比当前系统可用内存更多的内存。这是有道理的,因为大部分进程从来不会用掉它们请求的所有内存。就像有线网络运营商,他们承诺每个用户100Mbit的下载速度,这远远超出了运营商网络的真实带宽。因为他们认为所有用户不会同时达到带宽的上限。所以,一个10Gbit的链路能够很好地为100个用户提供服务超。
这种机制的一个副作用是,一些程序会消耗系统内存。这将导致内存不足,使得没有内存页面可以分配给进程。你可能遇到过这种情况,只有root账号才能杀掉offending任务。为了避免这种情况发生,杀手进程会被启动,识别进程并杀死它。
更多关于“内存不足杀手”的内容请参见这篇RedHad的文档。
现在,我们知道了一些背景知识,但是内存不足杀手由谁触发?究竟什么原因让我在早上5点被叫醒?一些调查显示:
/proc/sys/vm/overcommit_memory中的配置允许过量使用内存,它被设置为1,意味着每一次malloc都能够成功申请到内存。
应用运行在一个EC2 m1.small实例上。EC2实例默认是不支持交换区的。
这两点再加上突然增加的访问导致了我们的应用会申请越来越多的内存以支持这些用户。过量使用内存配置也允许为这些进程申请越来越多的内存,最后触发了“内存不足杀手”,就像它的名字那样,杀死我们的应用然后在半夜把我叫醒。
当我向工程师们描述这个问题时,有一个很有兴趣的工程师用一个小测试程序来复现这个问题。当在Linux(最新稳定版Ubuntu)上编译和加载下面的Java代码片段时,
你会发现类似下面的消息:Kill process (java) score 或牺牲子进程的消息。
注意:你可能需要修改交换区和堆大小。在我的测试程序中,将堆大小通过-Xmx2g设置成2G,通过如下配置设置交换区大小:
有很多种方法可以解决这个问题。在我们的示例中,我们只是把系统迁移到一个有更大内存的实例中。并且我还建议允许交换,但是当咨询过工程人员后,我意识到Java虚拟机中的垃圾回收进程在交换时表现不是很好,所以这个选项最后没有被采用。
其他可能有用的方案包括微调内存不足杀手,在几个实例间进行负载均衡或者降低应用的内存需求。
原文链接:javacodegeeks,译文链接:http://www.importnew.com/12285.html
早上6点,我不得不开始处理“叫醒”我的一些问题。因为当这些问题发生的时候,我的手机铃声响了。昏睡中的我非常不情愿地拿起了手机,检查我是否疯狂到将叫醒闹钟设在了早上5点。原来是监控系统发现一个Plumbr服务死掉了。
作为一名该领域经验丰富的高手,我首先来到了咖啡机旁。我需要用一杯咖啡开始工作。第一个问题,在应用崩溃之前看起来一切运行正常。日志中没有错误,没有告警,也没有其他任何异常。
我们的监控系统已经察觉到进程死掉了,并且已经重启了崩溃的服务。因为血液中已经有了咖啡因,我开始收集更多的证据。30分钟后,在/var/log/kern.log文件中发现了以下内容:
理解“内存不足杀手”
默认情况下,Linux内核允许进程请求比当前系统可用内存更多的内存。这是有道理的,因为大部分进程从来不会用掉它们请求的所有内存。就像有线网络运营商,他们承诺每个用户100Mbit的下载速度,这远远超出了运营商网络的真实带宽。因为他们认为所有用户不会同时达到带宽的上限。所以,一个10Gbit的链路能够很好地为100个用户提供服务超。这种机制的一个副作用是,一些程序会消耗系统内存。这将导致内存不足,使得没有内存页面可以分配给进程。你可能遇到过这种情况,只有root账号才能杀掉offending任务。为了避免这种情况发生,杀手进程会被启动,识别进程并杀死它。
更多关于“内存不足杀手”的内容请参见这篇RedHad的文档。
内存不足杀手由谁触发?
现在,我们知道了一些背景知识,但是内存不足杀手由谁触发?究竟什么原因让我在早上5点被叫醒?一些调查显示:/proc/sys/vm/overcommit_memory中的配置允许过量使用内存,它被设置为1,意味着每一次malloc都能够成功申请到内存。
应用运行在一个EC2 m1.small实例上。EC2实例默认是不支持交换区的。
这两点再加上突然增加的访问导致了我们的应用会申请越来越多的内存以支持这些用户。过量使用内存配置也允许为这些进程申请越来越多的内存,最后触发了“内存不足杀手”,就像它的名字那样,杀死我们的应用然后在半夜把我叫醒。
示例
当我向工程师们描述这个问题时,有一个很有兴趣的工程师用一个小测试程序来复现这个问题。当在Linux(最新稳定版Ubuntu)上编译和加载下面的Java代码片段时,注意:你可能需要修改交换区和堆大小。在我的测试程序中,将堆大小通过-Xmx2g设置成2G,通过如下配置设置交换区大小:
解决方案?
有很多种方法可以解决这个问题。在我们的示例中,我们只是把系统迁移到一个有更大内存的实例中。并且我还建议允许交换,但是当咨询过工程人员后,我意识到Java虚拟机中的垃圾回收进程在交换时表现不是很好,所以这个选项最后没有被采用。其他可能有用的方案包括微调内存不足杀手,在几个实例间进行负载均衡或者降低应用的内存需求。
相关文章推荐
- 内存不足:杀死进程还是牺牲子进程
- 内存不足:杀死进程还是牺牲子进程
- Oracle EBS 大量并发请求提交导致内存不足系统杀死Java JVM进程
- 第29课:彻底解密Spark 1.6.X以前Shuffle中JVM内存使用及配置内幕详情:Spark到底能够缓存多少数据、Shuffle到底占用了多少数据、磁盘的数据远远比内存小却还是报告内存不足?
- java.sql.SQLException: ORA-04030: 在尝试分配 64528 字节 (sort subheap,sort key)时进程内存不足?
- 内存不足时Android 系统如何Kill进程
- kill 命令杀死父进程和所有子进程
- ORA-04030: 在尝试分配...字节(...)时进程内存不足的原因分析解决方法
- Android模拟内存不足,App在后台被杀死的情况
- ORA-04030: 在尝试分配 123416 字节 (QERHJ hash-joi,kllcqas:kllsltba) 时进程内存不足
- Oracle HowTo:如何快速杀死占用过多资源(CPU,内存)的数据库进程
- 安卓强制杀死进程的几种方法收集汇总,不足之处请包涵。
- Linux OOM-killer(内存不足时kill进程的策略)
- 主进程退出的时候,杀死所有子进程
- 主进程被杀死时,如何保证子进程同时退出,而不变为孤儿进程(二)
- 主进程被杀死时,如何保证子进程同时退出,而不变为孤儿进程(三)
- 主进程退出的时候,杀死所有子进程
- Android 系统如何Kill进程当系统内存不足【原理】
- 内存不足导致OpenStack进程异常的诊断和思考
- 到底是 Activity 被回收了还是进程被杀死了?