ENOMEM从系统()popen(),而有足够的内存

我有两个相对较大的应用程序(进程)运行在ARM上的ARM与3个RAM银行(在Linux cmdline:mem = 128M mem = 256M @ 0x90000000 mem = 128M @ 0xA0000000)。 一个应用程序处理用户命令,其间可能会有请求运行普通的Linux shell命令。 这被实现为:

if((fp=popen(UserCommand, "r")) == NULL) return(errno)); fgets(ReplyString, 128, fp); Res = pclose(fp);

第一行返回errno = 12 – ENOMEM,即使是像“pwd”这样的最简单的命令,虽然内存很多:

root@dm814x-evm:~# free total used free shared buffers Mem: 461472 38576 422896 0 152 Swap: 0 0 0 Total: 461472 38576 422896

据我所知,有超过400MB的可用空间!
对于第一个testing目的,我也取消了第二个过程 – 操作!错误已经消失!
对于第二个testing,我运行telnet并通过它执行命令(而这两个进程都在运行) – 没问题,工作正常。

那么,在哪里捕捉?

如果使用fork() (因为它当前在glibc中)而不是posix_spawn()vfork()来实现popen,那么您需要尽可能多的内存作为操作成功的父项。 如果您的系统上的overcommit被禁用,则此分配可能会失败,因此要解决您的问题,您应该执行以下操作之一:

  1. 完全启用您的系统overcommit

     sudo sh -c 'echo 1>/proc/sys/vm/overcommit_memory' 
  2. fork() ( musl就是一个例子 )使用一个libc库不能实现popen()

  3. 做什么popen自己,但是用pipe()posix_spawn() ,而不是古典的pipe()dup2()fork()execve()组合。

popen 1)创建一个管道2)将管道的一端封装在FILE ,3)创建一个进程并将管道的另一端连接到进程的stdinstdout ,将进程的pid保存在FILE结构中)

传统的fork() + execve()方法创建过程的问题是,如果overcommit被禁用, fork()必须是悲观的,并假定子进程可能继续运行父进程,这意味着子进程需要父母的记忆。 启用overcommit后,内存被借用,而且只有在借用内存被访问的情况下(如果进程将立即调用execve()才会出现问题(内存不足的杀手)。 禁用overcommit时,所有的内存都必须被保留,这就是为什么如果fork调用是从一个更大的进程中产生的话可能会失败。