0x01 缘由
当将生产环境换为64bit后,系统内存的问题全部显现,内存耗尽、内存占用大,导致内存耗尽,吃掉交换分区内存,然后系统卡、卡、卡... ...
0x02 知识点
linux c 编程资源限制:
API: 能够通过函数getrlimit()、setrlimit()分别获得、设置每个进程能够创建的各种系统资源的限制使用量。
命令行:ulimit -a
0x03 TOP显示含义再次学习
VIRT:virtual memory usage 虚拟内存
1、进程“需要的”虚拟内存大小,包括进程使用的库、代码、数据等
2、假如进程申请100m的内存,但实际只使用了10m,那么它会增长100m,而不是实际的使用量
RES:resident memory usage 常驻内存
1、进程当前使用的内存大小,但不包括swap out
2、包含其他进程的共享
3、如果申请100m的内存,实际使用10m,它只增长10m,与VIRT相反
4、关于库占用内存的情况,它只统计加载的库文件所占内存大小
SHR:shared memory 共享内存
1、除了自身进程的共享内存,也包括其他进程的共享内存
2、虽然进程只使用了几个共享库的函数,但它包含了整个共享库的大小
3、计算某个进程所占的物理内存大小公式:RES – SHR
4、swap out后,它将会降下来
DATA
1、数据占用的内存。如果top没有显示,按f键可以显示出来。
1、数据占用的内存。如果top没有显示,按f键可以显示出来。
2、真正的该程序要求的数据空间,是真正在运行中要使用的。
0x03 做法1-进程中调用API
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <errno.h>
#include <iostream>
// 用于内存不足的情况下程序退出
static char *reservedMemoryForExit;
void outOfMemoryHandler()
{
static bool isInHandler = false;
if (isInHandler) return;
isInHandler = true;
// 释放保留内存,以免程序退出过程中再次出现内存不足
delete[] reservedMemoryForExit;
reservedMemoryForExit = NULL;
printf("Memory Not Enough exit");
abort();
}
void initNewOperHandler()
{
const int RESERVED_MEM_SIZE = 1024 * 1024 * 2; // 2M
std::set_new_handler(outOfMemoryHandler);
// 用于内存不足的情况下程序退出
reservedMemoryForExit = new char[RESERVED_MEM_SIZE];
}
int main(void)
{
int nMemoryLimit = 1024 * 1024 * 20;//5M
struct rlimit64 memoryL;
getrlimit64(RLIMIT_AS, &memoryL);
printf("before set mem:%lu,%lu\r\n", (unsigned long)memoryL.rlim_cur, (unsigned long)memoryL.rlim_max);
memoryL.rlim_cur = nMemoryLimit;
memoryL.rlim_max = nMemoryLimit;
setrlimit64(RLIMIT_AS ,&memoryL);
getrlimit64(RLIMIT_AS, &memoryL);
printf("after set mem:%lu,%lu\r\n", (unsigned long)memoryL.rlim_cur, (unsigned long)memoryL.rlim_max);
initNewOperHandler();
int i = 0;
while(1)
{
i++;
//当进程内存达到最大值时,malloc calloc返回NULL,记录错误errno=ENOMEM
errno = 0;
char *psString = (char *)calloc(1, 1024);
if(NULL == psString)
{
printf("errno=%d, ENOMEM=%d\r\n", errno, ENOMEM);
}
else
{
printf("success, %d\r\n", i);
}
}
return 0;
}
0x04 做法5-利用/proc/pid/status
代码:
{
char file[64] = { 0 };//文件名
FILE *fd; //定义文件指针fd
char lineBuff[256] = { 0 }; //读取行的缓冲区
sprintf(file, "/proc/%d/status", pid);
fd = fopen(file, "r"); //以R读的方式打开文件再赋给指针fd
//获取vmrss:实际物理内存占用
int i;
char name[32];//存放项目名称
int vmrss;//存放内存
//读取VmRSS这一行的数据
for (i = 0; i < VMRSS_LINE - 1; i++)
{
char* ret = fgets(lineBuff, sizeof(lineBuff), fd);
}
char* ret1 = fgets(lineBuff, sizeof(lineBuff), fd);
sscanf(lineBuff, "%s %d", name, &vmrss);
fclose(fd); //关闭文件fd
memTotal = vmrss / 1024;
return memTotal;
}
0x05 总结
如果在同一台服务器上需要做资源隔离,可以采用cgroup\taskset等技术完善,内存泄露的问题是必须解决的。以上方法是产品压力较大时的临时解决办法。