文档章节

内存不足导致不能执行system

青春无极限
 青春无极限
发布于 2018/03/28 14:29
字数 1398
阅读 369
收藏 0

问题分析:

1.本来向板子发送个reboot,板子程序收到reboot命令后会执行system(“reboot”);

但是板子并没有重启。

2.分析system执行机制

先来看一下system()函数的简单介绍:

#include
int system(const char *command)

system()函数调用/bin/sh来执行参数指定的命令,/bin/sh 一般是一个软连接,指向某个具体的shell,比如bash,-c选项是告诉shell从字符串command中读取命令; 在该command执行期间,SIGCHLD是被阻塞的,好比在说:hi,内核,这会不要给我送SIGCHLD信号,等我忙完再说; 在该command执行期间,SIGINT和SIGQUIT是被忽略的,意思是进程收到这两个信号后没有任何动作。

再来看一下system()函数返回值:

为了更好的理解system()函数返回值,需要了解其执行过程,实际上system()函数执行了三步操作:

  1. fork一个子进程;
  2. 在子进程中调用exec函数去执行command;
  3. 在父进程中调用wait去等待子进程结束。 对于fork失败,system()函数返回-1。 如果exec执行成功,也即command顺利执行完毕,则返回command通过exit或return返回的值。 (注意,command顺利执行不代表执行成功,比如command:"rm debuglog.txt",不管文件存不存在该command都顺利执行了) 如果exec执行失败,也即command没有顺利执行,比如被信号中断,或者command命令根本不存在,system()函数返回127. 如果command为NULL,则system()函数返回非0值,一般为1.

看一下system()函数的源码

int system(const char * cmdstring)  
{  
    pid_t pid;  
    int status;  
  
if(cmdstring == NULL)  
{  
    return (1); //如果cmdstring为空,返回非零值,一般为1  
}  
  
if((pid = fork())<0)  
{  
    status = -1; //fork失败,返回-1  
}  
else if(pid == 0)  
{  
    execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);  
    _exit(127); // exec执行失败返回127,注意exec只在失败时才返回现在的进程,成功的话现在的进程就不存在啦~~  
}  
else //父进程  
{  
    while(waitpid(pid, &status, 0) < 0)  
    {  
        if(errno != EINTR)  
        {  
            status = -1; //如果waitpid被信号中断,则返回-1  
            break;  
        }  
    }  
}  
  
    return status; //如果waitpid成功,则返回子进程的返回状态  
}  

由于返回值是-1,因此比较怀疑fork执行失败。在控制台上输入fork后,果然返回-1。fork返回-1主要由两种原因:系统达到最大进程数上限或者系统内存不足。由于系统当前进程数并不多,因此怀疑内存不足。 
0803版本中升级了由于CPUH内存空间不足,导致升级失败的问题。这个问题是通过将CPUL的100M内存挪至CPUH解决的。至此,问题已基本明确,确实是由于挪动内存后,CPUL上的剩余内存不足以fork。 
其实这里我有一个疑问,fork会复制父进程的数据空间、堆和栈的副本。因此,如果父进程的内存占用超过系统总可用内存的50%,调用system或fork就会存在风险。而linux提供了另外一个函数:vfork。vfork并不会复制父进程的完整地址空间,这个函数主要应用的场景就是fork后,立即调用exec(exec会使用新程序替换掉当前进程的正文段、数据段、堆和栈)。按照上面提到的fork流程,fork时需要大量的内存来存放父进程的地址空间,而在exec时又会立即用新程序替换掉。对于system调用失败,仅仅是由于内存不足以容纳另一份父进程地址空间,未免有点冤了。而直接使用vfork,则空闲内存并不需要那么大,system为何没有使用更合适的vfork呢?

解决

有两个解决方案,一个是重新调整CPUL以及CPUH的内存分配,另一个是调整内核参数。 
其中方案1存在一定的风险,因为内存的使用是动态的,如果分回来的过多,可能导致CPUH再次出现偶尔升级失败,如果分过来的不够,则有可能出现CPUL调用system失败,因此,这里主要考虑使用方案2。 
在前面分析的过程中,已经明确,是由于触发了Linux的虚拟内存保护,导致fork失败。可以通过修改/proc/sys/vm/overcommit_memory的值,来修改系统的虚拟内存保护策略。这个文件可以取0、1、2三个值,含义如下: 
 0-Heuristic overcommit handling 
0是LINUX系统的默认值。允许进程申请的内存超出一个合理(reasonable)值,如果进程申请超出的过多,则内存分配会被拒绝。如果进程超出范围在合理值内,则也有可能触发omm-kill,导致进程被杀死。 
 1-Always overcommit 
接收进程申请的任何内存大小 
 2-Don’t overcommit 
不允许超出内存总量。内存总量受另外一个参数overcommit_ratio控制,系统总可用内存计算公式如下: 
总可用内存 = (swap space + RAM size * overcommit_ratio) 
可以使用该选项为系统预留一定量的内存。overcommit_ratio参数可通过修改/proc/sys/vm/overcommit_ratio设置。 
考虑到我们的代码中出了system外,并没有fork的需求,而且system在执行fork后会立即调用exec释放掉申请的空间,因此我们将overcommit_memory设置为1。

 

解决方法:

在启动脚本里增加:

echo 1 > /proc/sys/vm/overcommit_memory &

 

© 著作权归作者所有

上一篇: setjmp与 longjmp
下一篇: spyder安装库
青春无极限
粉丝 2
博文 129
码字总数 71498
作品 0
卢湾
程序员
私信 提问
MySQL · 专家投稿 · MySQL数据库SYS CPU高的可能性分析

问题背景 我们在管理繁忙的 MySQL 数据库时,可能都有碰到 SYS CPU 高的经历:系统突然 SYS CPU 高起来,甚至比 USER CPU 高很多,这时系统 QPS、TPS 急剧下降。 SYS CPU高是什么造成的呢?主...

阿里云RDS-数据库内核组
2015/05/03
0
0
触发JVM进行Full GC的情况及应对策略

堆内存划分为 Eden、Survivor 和 Tenured/Old 空间,如下图所示: 从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC,对老年代GC称为Major GC,而Full GC是对整个堆来说的...

八戒_o
2016/02/22
75
0
hadoop 0.20.2 cdh3u6 运行单节点任务卡死,但不报错,问题分析。

背景: 单节点运行hadoop所有组件(namenode,datanode,jobtracker,tasktarcker等)运行任务后,所有任务卡死,无法继续运行。使用oozie管理job。 分析: 查看hadoop日志并没有发现错误,因此...

parker
2016/02/19
157
1
Android BroadcastReceive广播详解

版权声明:没事随便转 https://blog.csdn.net/qq_41816123/article/details/85137492 定义 是一个全局的监听器 工作原理 使用流程 自定义广播接收者BroadcastReceiver 继承BroadcastReceivre...

齐码闯天涯
2018/12/20
0
0
JVM 堆外内存

JVM 堆外内存 青蜂侠2017-11-0422 阅读 JVM内存 1. 何谓堆外内存 在之前的文章里面讲了 JVM结构 ,着重讲了JVM堆结构,这里的堆外内存就是相对于JVM堆而言的,主要包含jvm本身在运行过程中分...

青蜂侠
2017/11/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【2019个推开发者节】航母级APP都在用的SDK现在全部免费,35岁老程序员表示第一次见!

1024程序员节来了 双11近了 各路满减、折扣、领券、秒杀、集赞 营销玩法猛于虎,一看优惠两毛五 日常拼命赶“需求” 修“Bug”的开发者们 想找个好用又不贵的工具太难了 亲爱的开发者们,不要...

个推
34分钟前
9
0
Ceph对可用存储空间的校验与控制

Ceph一共使用了四个配置对可用存储空间进行校验并实施控制,如下: mon_osd_full_ratio:集群中的任一OSD空间使用率大于等于此数值时,集群将被标记为Full,此时集群将停止接受来自客户端的写...

浪里个浪浪
36分钟前
11
0
工厂方法模式

1.定义:创建一个接口,协助创建其它对象 2.优缺点 优: a.用户只需要知道这个工厂是创建哪种对象的,不需要知道创建的过程 b.满足开闭原则(开闭原则:对扩展开放,对修改关闭,即增加类可以...

wen123
37分钟前
6
0
Bootstrap Table -detailView和detailFilter的使用

查看表格 detailFilter 属性:data-detail-filter Type:Function Default:function(index,row){ return true} detailView 属性:data-detail-view Type:Boolean Default:false <table id="ta......

tianyawhl
42分钟前
4
0
场效应管的注意事项

  (1)为了安全使用场效应管,在线路的设计中不能超过管的耗散功率,最大漏源电压、最大栅源电压和最大电流等参数的极限值。   (2)各类型场效应管在使用时,都要严格按要求的偏置接入...

仙溪
45分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部