通过top发现,JavaA大部分时间占用的内存实际并不多,但是占用的虚拟内存很大。马上修改该程序启动时的
JVM参数,将最大内存调的小一些,果然就不出错了。由于JavaA必须在内存中处理大量的数据,内存太小了就可
能处理不了,因此这么改是不可行的。
上网查的过程中,发现一些有趣的东西。Linux内核中可以设置内存的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()还没有执行,于是悲剧就发生了,内存都要重新复制一遍。
解决办法
最后说说解决办法,既然问题出在可能会申请分配跟父进程同等大小的内存,那么我限制父进程使用的内存就
可以了。前面说了我们正在开发的JavaA必须使用比较大的内存,可是JavaA不一定是父进程呀,我可以单独运
行一个Java程序,称为JavaB吧,由它负责调用外部程序,JavaA调用我们封装后的接口与之通信,等待外部程
序结束,从而与Runtime.getRuntime().exec(cmd)的语义保持一致。这个单独运行的JavaB只需要很小很小的内
存,因此不太可能出现无法分配内存,进而无法执行外部程序的问题了
相关推荐
windows环境下IDEA java代码Runtime.getRuntime.exec中shell的执行环境的解决方案前言解决办法后记 前言 在使用IDEA本地开发监控守护线程的后台,我遇上了执行环境不兼容的问题,爆出各种“xxx不是内部或外部命令,...
主要介绍了详解Java8与Runtime.getRuntime().availableProcessors(),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
1,申请root权限Runtime.getRuntime().exec("su"); 2,通过数据输出流DataOutputStream写入pm install命令; 3,最后获取Process进程的返回值int i = process.waitFor();,如果i=0,则表明已获取root权限。
完美解决runtime.exec()执行进程block死锁以及为waitFor设置超时 不需要耗cpu的循环判断exitValue==0 开两个进程搞定
Runtime 执行bat
Runtime rt = Runtime.getRuntime(); int RC = -1; try { Process p = rt.exec(args); int bufSize = 4096; BufferedInputStream bis =new BufferedInputStream(p.getInputStream(), bufSize); int len; byte buffer...
这里不是通过view来截图,也不是通过底层的framebuffer实现截图,而是采用另外一种方法实现截图,通过Runtime.getRuntime().exec()来实现,并保存在sdcard上,代码很简单。
java的Runtime.getRuntime().exec(commandStr)可以调用执行cmd指令。 cmd /c dir 是执行完dir命令后关闭命令窗口。 cmd /k dir 是执行完dir命令后不关闭命令窗口。 cmd /c start dir 会打开一个新...
Runtime runtime = Runtime.getRuntime(); try { runtime.exec("cmd /c start " + url); } catch (IOException e) { e.printStackTrace(); } } /** * 鍦ㄥ欢杩熸寚瀹氱殑绉掓暟鍚庡叧鏈? * ...
Java调用Linux命令 调用Runtime.exec方法将产生一个本地的进程,并返回一个Process子类的实例, (注意:Runtime.getRuntime().exec(command)返回的是一个Process类的实例), 该实例可用于控制进程或取得进程的...
主要介绍了Java编程使用Runtime和Process类运行外部程序的方法,结合实例形式分析了java使用Runtime.getRuntime().exec()方法运行外部程序的常见情况与操作技巧,需要的朋友可以参考下
所以我们必须到Dos环境下去设置,在java中用Runtime.getRuntime().exec("attrib " + """ + file.getAbsolutePath()+ """+ " +R")该方法可以实现。因为路径file.getAbsolutePath()中可能会还有空格,所以必须...
直接看代码:方法一: 代码如下:Runtime.getRuntime().exec(“rundll32 url.dll,FileProtocolHandler //www.jb51.net”); 方法二: 代码如下://判断当前系统是否支持Java AWT Desktop扩展 if(java.awt....
//Process p = Runtime.getRuntime().exec("su"); //然后,在向这个进程的写入要执行的命令,即可达到以root权限执行命令: //dos.flush(); //或者用下面的方式: //Runtime.getRuntime().exec&#...
蜂鸣器exe,可用java调用 Runtime.getRuntime().exec("d:\\beep.exe");
System.out.println("Runtime.getRuntime().maxMemory()="+Runtime.getRuntime().maxMemory()); 而且确实,现有检测工具底层也是用这个语句来进行检测。要解决这个问题,首先我们需要一个可重复使用的测试用例。因此...
动态权限工具类
su = Runtime.getRuntime().exec("/system/bin/su"); /*String cmd = "chmod 777 " + device.getAbsolutePath() + "\n" + "exit\n";*/ String cmd = "chmod 777 /dev/s3c_serial0" + "\n" + ...
利用Runtime call操作系统的命令,具体的命令取决于不同的操作系统,注意不要调用Runtime.getRuntime().exec(String)接口,要用Runtime.getRuntime().exec(String[])这个接口,不然复杂命令的执行会有问题。...