文档章节

Java执行Runtime.exec(shell)报Cannot allocate memory

山哥
 山哥
发布于 2014/06/05 17:05
字数 1118
阅读 4967
收藏 11

在Linux下用java的Runtime.getRuntime().exec(cmd)方式,执行shell脚本时,遇到“Cannot allocate memory”的错误。

网上查询资料整理如下:

Cannot allocate memory

在Linux上调试一个比较复杂的Java程序,称为JavaA吧,JavaA会频繁的通过Process proc = Runtime.getRuntime().exec(cmd);调用一些外部程序。在系统负载和该程序占用内存都比较大的情况下,会出现调用失败的情况,错误信息是:"Cannot allocate memory"。


overcommit_memory

通过top发现,Java A大部分时间占用的内存实际并不多,但是占用的虚拟内存很大。马上修改该程序启动时的JVM参数,将最大内存调的小一些,果然就不出错了。由于JavaA必须在内存中处理大量的数据,内存太小了就可能处理不了,因此这么改是不可行的。

上网查的过程中,发现一些有趣的东西。Linux内核中可以设置内存的overcommit_memory属性(设置方法:echo 1 > /proc/sys/vm/overcommit_memory),意思是Linux内核认为有些程序很保守,总是申请较多的内存,但实际并不使用,因此在设置overcommit后,内核将不检查剩余内存是否够用,直接允许所有的内存分配。可能大部分情况下没问题,但是仔细想想,还是有很大的问题,最严重的是改变了malloc的语义,调用者不能通过返回值来判断内存是否分配成功了。另外一个问题是,万一内存真的不够了怎么办?Linux中有个特殊的进程,OOM(out-of-memory)进程终止者,其功能就是在内存真的不够时,随机或者根据某些原则杀掉一些进程。选择进程的原则好像不能精确控制,那将是一件很恐怖的事情。。。


Runtime.getRuntime().exec(cmd) 的执行流程分析

继续上网查,大概意思是Java程序调用外部程序时可能需要分配跟父进程同等大小的内存。这就奇怪了,比如说,我随便调用一下ls命令,也需要很多内存吗?肯定是Java调用外部程序的接口里处理比较特殊。嗯,刚好JDK也开源,看看源码去。

分析SUN JDK 1.5 SRC,找到Runtime.getRuntime().exec(cmd)的执行流程:

java.lang.Runtime.exec(cmd);

--java.lang.ProcessBuilder.start();

----java.lang.ProcessImpl.start();

------Java_java_lang_UNIXProcess_forkAndExec() in j2se/src/solaris/native/java/lang/UNIXProcess_md.c

--------1). fork(); 2). execvp();

man fork知道,fork产生的子进程需要复制父进程在内存中的所有数据内容(代码段、数据段、堆栈段),由于全部复制开销较大,因此Linux已经采用copy-on-write机制,即只是复制页表,共享内容,在有改变的时候再去申请内存和复制数据。

因此我分析,问题的原因可能是这样的,虽然Linux早已在fork()中采用copy-on-write机制,但是JVM调用fork()后,Java进程里的其它线程往往会被调度回来继续执行,修改了自己的内存,而这个时候execvp()还没有执行,于是悲剧就发生了,内存都要重新复制一遍。

 

解决办法

方法一(不推荐):修改 overcommit_memory值:echo 1 > /proc/sys/vm/overcommit_memory

方法二: 既然问题出在可能会申请分配跟父进程同等大小的内存,那么我限制父进程使用的内存就可以了。前面说了我们正在开发的JavaA必须使用比较大的内存,可是JavaA不一定是父进程呀,我可以单独运行一个Java程序,称为JavaB吧,由它负责调用外部程序,JavaA调用我们封装后的接口与之通信,等待外部程序结束,从而与 Runtime.getRuntime().exec(cmd) 的语义保持一致。这个单独运行的JavaB只需要很小很小的内存,因此不太可能出现无法分配内存,进而无法执行外部程序的问题了。

方法三:针对Tomcat的Web应用,我们习惯在catalina.sh中进行JVM的内存优化配置:

JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms256m -Xmx1024m -XX:NewSize=64m -XX:MaxNewSize=512m -XX:PermSize=64m -XX:MaxPermSize=512m -XX:+DisableExplicitGC"

注意,我们要把 -Xms, -XX:NewSize, -XX:PermSize 的内存大小设置一个较小的值,这样才能保证不出现 Cannot allocate memory 异常。

本文转载自:http://blog.csdn.net/vernonzheng/article/details/8644936

共有 人打赏支持
山哥

山哥

粉丝 245
博文 351
码字总数 136465
作品 0
南京
程序员
私信 提问
加载中

评论(1)

w
winston952
麻烦帮我看看 :https://www.oschina.net/question/3891467_2284301 这个问题 是不是主进程分配的内存过大呢
执行Runtime.exec异常: error=12,Cannot allocate memory

Exception Trace: In the Linux circumstance, when the program executes till this place: Process p = Runtime.getRuntime().exec(cmdArr); it throws an exception like this: java.i......

疯狂的艺术家
2012/02/06
0
1
对Java Stack的一次探索

问题说明 昨天发现线上有一些业务逻辑没有执行到,但是代码入口代码日志已经打印,深入下去一看,底层库里有一个事件执行的方法在每次执行时都会 new 一个 thread,在以往量不大时没有问题,...

52iSilence7
10/31
0
0
在部署rocketMQ之后运行mqnamesrv报异常

安装好rocketMQ,配置好环境变量之后,运行mqnamesrv查看日志发现有如下的异常,好像是因为无法分配内存,请了解的大神知道一下看看是什么错误? 环境:vmware ubuntu jdk8 1G内存 Java HotSp...

少不读水浒
2015/11/23
5.1K
4
禁止JVM执行外部命令Runtime.exec -- 由Apache Commons Collections漏洞引发的思考

update: 2015-11-16 新版apache commons collections 3.2.2修复漏洞 新版本的apache commons collections默认禁止了不安全的一些转换类。可以通过升级来修复漏洞。参考release说明:https:/...

横云断岭
2015/11/13
0
0
java -version报错

问题描述,执行命令java -Xms8m -Xmx16m -version 报错 生成的log中:There is insufficient memory for the Java Runtime Environment to continue.Native memory allocation (malloc) fai......

风中之神
2015/06/17
346
1

没有更多内容

加载失败,请刷新页面

加载更多

jquery通过id显示隐藏

var $div3 = $('#div3'); 显示 $div3.show(); 隐藏 $div3.hide();

yan_liu
51分钟前
1
0
《乱世佳人》读书笔记及相关感悟3900字

《乱世佳人》读书笔记及相关感悟3900字: 之前一直听「荔枝」,后来不知怎的转向了「喜马拉雅」,一听就是三年。上班的时候听房产,买房了以后听装修,兴之所至时听旅行,分手后听亲密关系,...

原创小博客
54分钟前
1
0
大数据教程(9.6)map端join实现

上一篇文章讲了mapreduce配合实现join,本节博主将讲述在map端的join实现; 一、需求 实现两个“表”的join操作,其中一个表数据量小,一个表很大,这种场景在实际中非常常见,比如“订单日志...

em_aaron
今天
1
0
cookie与session详解

session与cookie是什么? session与cookie属于一种会话控制技术.常用在身份识别,登录验证,数据传输等.举个例子,就像我们去超市买东西结账的时候,我们要拿出我们的会员卡才会获取优惠.这时...

士兵7
今天
1
0
十万个为什么之为什么大家都说dubbo

Dubbo是什么? 使用背景 dubbo为什么这么流行, 为什么大家都这么喜欢用dubbo; 通过了解分布式开发了解到, 为适应访问量暴增,业务拆分后, 子应用部署在多台服务器上,而多台服务器通过可以通过d...

尾生
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部