提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
这是在实际项目中发现的bug,设备运行一段时间后出现报错:popen error:Cannot allocate memory。运行平台:新唐NUC970,内存64M ,linux内核版本:3.10.108+ 。
一、popen介绍
popen函数会创建了一个子进程来执行 shell,而 shell 又创建了一个子进程来执行命令,从实践过程可以看到,在进程分配内存沾满进程stack空间后,这些函数都是执行失败,返回ENOMEM 错误码Cannot allocate memory,只要不释放空间,都是一直执行失败的
二、popen error 原因分析
这里做了一个测试程序,复现问题:主线程malloc申请堆空间,把进程的堆栈空间沾满;另外一条线程执行popen操作。结果是:routine线程执行popen一直报popen error:Cannot allocate memory错误,直到主线程执行free操作。
1、设备的系统内存
2、运行测试程序./test ,MAX statck size刚好是8M
3、结果:在进程运行过程,使用堆空间超过8M后,就报错了,但是实际上系统内的内存还很充足,还有37M多的。
4、一旦把malloc申请的空间释放后,马上恢复正常
5、测试程序源码
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/sysinfo.h>
#define SIZE (1024*1024*1)
#define MEM_SIZE (45)
void *routine(void *arg)
{
struct sysinfo info;
while(1)
{
sysinfo(&info);
printf("freeram = %ld\n",info.freeram);
FILE* fp = popen("cat /sys/class/net/eth0/carrier", "r");
if(fp == NULL)
{
printf("popen error:%s\n", strerror(errno));
sleep(1);
continue;
}
char buffer[1024];
int bytes_read = fread(buffer, 1, sizeof(buffer), fp);
pclose(fp);
printf("popen ok %2x\n",buffer[0]);
sleep(1);
}
}
int main(int argc, char **argv)
{
pthread_t tid;
pthread_create(&tid, NULL, routine, NULL);
unsigned int *p = (unsigned int *)malloc(1024 * 1024 * MEM_SIZE);
printf("malloc buffer: %p\n", p);
for (int i = 0; i < 1024 * 1024 * (MEM_SIZE/sizeof(int)); i++)
{
p[i] = 123;
if ((i & 0xFFFFF) == 0)
{
printf("%dMB written\n", i >> 18);
sleep(1);
//usleep(100000);
}
}
while(1)
{
sleep(20);
if(p)
{
printf("free mem\n"); //内存释放后popen调用正常
free(p);
p = NULL;
}
}
return 0;
}
总结
popen这类函数系统开销很大,再进程内存紧张的情况下,很容易出错,没有及时把申请的内存空间释放,就一直执行失败的。解决办法下篇再讲解哦~~~