system函数调用失败
2016-12-07 21:08
369 查看
背景
项目在一次升级版本后,发现在DSP发生异常后,没有生成dspcrash文件。该文件通过system函数,直接调用可执行程序。后来增加定位信息,发现system返回-1。而在串口上直接调用可执行程序,执行成功。在控制台调用system函数,返回-1。system函数在该处理器上必现调用失败。定位
首先需要了解system的执行过程,实际上system执行了三步操作:1. fork一个子进程;
2. 在子进程中调用exec函数执行command;
3. 在父进程中调用wait等待子进程结束。
对于fork失败,system函数返回-1,;如果exec执行成功,则返回command通过exit或return返回的值;如果exec执行失败,system返回127。
由于返回值是-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。
相关文章推荐
- Android之WebView和js交互-调用失败的看这里
- SQL Server 2008安装程序失败在创建窗口句柄之前不能在控件上调用 Invoke 或 BeginInvoke
- 解决C#调用执行js报检索 COM 类工厂中 CLSID 为 {0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC} 组件失败
- SharePoint 2013 Foundation 报错: 试图调用服务应用程序时报告了失败: EndpointFailure 8313
- 代码调用服务--请求因 HTTP 状态 401 失败:Access Denied。(downmoon原创)
- 关于iOS sqlite3_prepare_v2 调用失败的问题
- 注册ActiveX控件时DllRegisterServer调用失败的解决方法
- ARM开发板上iconv_open(“utf-8", "gb2312”) 调用失败的解决方法
- osx平台调用curl_multi_exec失败脚本死循环
- 反射调用setMobileDataEnabled方法设置移动数据网络失败
- 代码调用服务--请求因 HTTP 状态 401 失败:Access Denied。(downmoon原创)
- SQL Server 2008R2 :远程调用失败
- win7 注册 卸载 报错: 模块 XXX 已加载 但对DllUnregisterServer 的调用失败 处理方法
- 调用系统成功失败函数
- QT线程QThread多次调用start()函数出现第2次调用失败问题备忘
- 【图像处理】A卡使用Emgucv时调用失败解决方法
- cxf客户端调用webservice接口,服务器端重启后调用失败,改为Restful方式调用
- SSIS调用存储过程失败
- Stanford CoreNLP 3.6.0 中文指代消解模块调用失败的解决方案
- Win10+python2.7.6+opencv2.4.13环境下, 调用cv2.VideoCapture()失败的解决方法