popen出错问题解决

问题

前天测试在4G拷机版本上报了一个问题,设备有很多出错打印,因为是新加的4G,之前没有这块的错误信息,发我看了下,发现是popen()出错

12:23:59:34[ERR][MyExe_WithCallback/43]:popen(lsusb) error.

12:23:59:34[ERR][L9XX_ParseCmd_LsUsb/48]:myexe error.

12:23:59:35[ERR][MyExe_WithCallback/43]:popen(lsusb) error.

12:23:59:35[ERR][L9XX_ParseCmd_LsUsb/48]:myexe error.

12:23:59:35[ERR][MyExe_WithCallback/43]:popen(route -n) error.

12:23:59:35[ERR][L9XX_ParseCmd_RouteGw/136]:myexe error.

12:23:59:35[ERR][__Net4G_UpdateRoute/171]:get default gateway error, exit

12:23:59:36[ERR][MyExe_WithCallback/43]:popen(lsusb) error.

12:23:59:36[ERR][L9XX_ParseCmd_LsUsb/48]:myexe error.

12:23:59:37[ERR][MyExe_WithCallback/43]:popen(lsusb) error.

12:23:59:37[ERR][L9XX_ParseCmd_LsUsb/48]:myexe error.

查看对应代码和出错行号,是popen()函数调用出错,出错部分代码如下:

         ptFile = popen(pcCmdStr,"r"); //建立管道

         if (!ptFile)

         {

                   MYERR("popen(%s)error.", pcCmdStr);

                   return -1;

         }

这是系统接口,怎么会调用出错??

原因定位

man查询popen函数说明

NAME

       popen, pclose - pipe stream to or from aprocess

SYNOPSIS

       #include

       FILE *popen(const char *command, constchar *type);

       int pclose(FILE *stream);

RETURN VALUE

       The popen() function returns NULL if thefork(2) or pipe(2) calls  fail,  or  if  it

       cannot allocate memory.

 

       The pclose()  function returns -1 ifwait4(2) returns an error, or some other error

       is detected.  In the event of an error, these functions seterrno  to indicate  the

       cause of the error.

返回值相关说明中,popen在fork()或pipe()或内存申请失败时会返回NULL。

 

没看出问题点,网上再查资料,总体上以下3份是说的比较清楚的:

A.     popen遇到ENOMEN的失败的bug调研

B.     使用popen遭遇ENOMEM (Cannot allocate memory)的问题

C.     还有一种是说内核针对内存分配的策略(/proc/sys/vm/overcommit_memory)导致

具体分析过程前人都做的不错了,这里不再重复,具体请打开超链接去查看。

 

解决办法1

先从能快速验证的C上做了试验,查了下内存分配的策略确实是0

# cat/proc/sys/vm/overcommit_memory

0

表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。

将它改为1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何

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

# sysctl -wvm.overcommit_memory=1

改完再测试,结果还是会出现报错问题。

 

解决办法2

C不行,从A、B上入手,A和B其实是同样的处理办法,自己实现一个类似popen()功能的vpopen()接口。

最主要的区别在于,popen()内使用fork()创建子进程,linux使用fork创建子进程会调用clone拷贝父进程的堆、栈、静态存储区、文件描述符等等,那么有可能父进程内存使用过多,导致子进程无法再从剩余的内存上分配内存。而vpopen()则改为vfork(),内部不会调用clone。

了解原理后,动手,也自实现vpopen()接口,不过我不放弃原popen函数,2个同时存在,先使用popen()处理,在出错时才调vpopen()处理,再测试验证,发现真的有用,拷了一段时间后,出现popen()执行出错了,但vpopen()可以正常执行。

真是帅不过三天,在我以为问题就这样解决的时候,老天给我甩了个大锅盖,在popen()出错vpopen()正常的情况下再长期拷机,最后vpopen()也顶不住了,而且它的出错是会直接killed主程序!!

这锅大了,原来popen()不成功,顶多只是执行出错,4G功能无法使用而已,产品还是能在本地网络情况下正常使用,现在改进反而挂了!又得重新考虑解决方案。

 

最终解决办法

回到问题原因的源头,这些都是因为父进程的占用资源过多,导致popen()创建子进程时内存不足,解决办法不就是优化减少父进程内存使用量嘛,理是这么个理,可这是主进程,上面的功能与应用逻辑都非常多,内存需求确实不少,做内存优化谈何容易!

换了个思路,既然主程内存使用大,把popen()改到另一个没多少内存使用的进程B上,再做一个网络通信实现主程与小进程B交互,相当于远程执行popen(),完美解决,长期拷机再也没出现popen()失败问题!

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值