This question is a M(not)WE of this question. I wrote a code that reproduces the error:
#include
#include
#include
The system()
function works by first creating a new copy of the process with fork()
or similar (in Linux, this ends up in the clone()
system call, as you show) and then, in the child process, calling exec
to create a shell running the desired command.
The fork()
call can fail if there is insufficient virtual memory for the new process (even though you intend to immediately replace it with a much smaller footprint, the kernel can't know that). Some systems allow you to trade the ability to fork large processes for reduced guarantees that page faults may fail, with copy-on-write (vfork()
) or memory overcommit (/proc/sys/vm/overcommit_memory
and /proc/sys/vm/overcommit_ratio
).
Note that the above applies equally to any library function that may create new processes - e.g. popen()
. Though not exec()
, as that replaces the process and doesn't clone it.
If the provided mechanisms are inadequate for your use case, then you may need to implement your own system()
replacement. I recommend starting a child process early on (before you allocate lots of memory) whose sole job is to accept NUL
-separated command lines on stdin
and report exit status on stdout
.
An outline of the latter solution in pseudo-code looks something like:
int request_fd[2];
int reply_fd[2];
pipe(request_fd);
pipe(reply_fd);
if (fork()) {
/* in parent */
close(request_fd[0]);
close(reply_fd[1]);
} else {
/* in child */
close(request_fd[1]);
close(reply_fd[0]);
while (read(request_fd[0], command)) {
int result = system(command);
write(reply_fd[1], result);
}
exit();
}
// Important: don't allocate until after the fork()
std::vector<double> a(7e8,1); // allocate a big chunk of memory
int my_system_replacement(const char* command) {
write(request_fd[1], command);
read(reply_fd[0], result);
return result;
}
You'll want to add appropriate error checks throughout, by reference to the man pages. And you might want to make it more object-oriented, and perhaps use iostreams for your read and write operations, etc.
Your line
std::vector<double> a(7e8,1);
is probably wrong. You are calling a constructor for std::vector which takes a vector size and an initializing element. The 7e8 is converted to a huge size (i.e. to 700000000 elements).
You might want to construct a two-element vector, so use
std::vector<double> a{7e8,1};
And with your huge vector, system(3) library function will call fork(2) system call which is failing with:
ENOMEM
fork()
failed to allocate the necessary kernel structures because memory is tight.
Maybe you reached some limit, e.g. set by setrlimit(2) somewhere else.
Try cat /proc/self/limits
to find them (on Linux).
Use strace(1) (e.g. as strace -f yourprogram
) to find out what is happening; look around the fork
or clone
line...
BTW, system(3) should return an error code on failure. You should test it. And you might want to call system("echo here pid $$");
instead of system(NULL);