reliability of proc/statm for finding memory leak

28 浏览
0 Comments

reliability of proc/statm for finding memory leak

我正在试图找到一个大型应用程序中的慢性内存泄漏。\nps 显示 VSZ 在运行了12-18小时后缓慢增长,最终导致应用程序崩溃。不幸的是,valgrind、leakcheck等工具都没有用(Valgrind出现非法指令错误)。\n另外,我一直在打印 /proc/statm 的内容,每隔大约10秒我会看到 statm 的第一个字段(程序总大小)增加20-30字节。\n我已经追踪到了一个函数,但是它没有意义。这个有问题的函数读取一个目录并在一个 std::set 上执行 clear() 操作。在函数中会导致内存占用增加的是什么?而且...为什么一旦目录关闭后内存不会减少?\n跟踪输出:\n

DvCfgProfileList::obtainSystemProfileList() PRE MEMORY USAGE: 27260 11440 7317 15 0 12977 0
DvCfgProfileList::obtainSystemProfileList() MID 1 MEMORY USAGE: 27296 11440 7317 15 0 13013 0
DvCfgProfileList::obtainSystemProfileList() MID 2 MEMORY USAGE: 27296 11443 7317 15 0 13013 0
DvCfgProfileList::obtainSystemProfileList POST MEMORY USAGE: 27288 11443 7317 15 0 13005 0

\n重要问题\n我可以依靠读取 /proc/statm 来立即获取进程内存的读数吗?这个 Unix/Linux 帖子表示它在“每次访问时更新”。\n如果是真的,那么为什么它显示 obtainSystemProfileList() 发生了泄漏?\n编辑 I\n我添加了对 Unix/Linux 帖子的链接。所以如果对 /proc/.../statm 的读取导致了直接和即时的内核调用,那么内核更新自己的内部结果是否有一些时间延迟?如果代码片段中确实没有内存泄漏,那么还有什么解释几行代码之间的 mem 值的变化?\n编辑 II\n调用 getrusage() 是否可以提供更即时和准确的进程内存使用情况?(还是只与读取 /proc/.../statm 一样,可能会有延迟的内核调用?)\n内核版本是32位的 3.10.80-1,如果有区别的话...\n代码片段:\n

bool
DvCfgProfileList::obtainSystemProfileList()
{
    TRACE(("DvCfgProfileList::obtainSystemProfileList() PRE "));
    DvComUtil::printMemoryUsage();
    DIR *pDir = opendir(SYSTEM_PROFILE_DIRECTORY);
    if (pDir == 0)
    {
        mkdir(SYSTEM_PROFILE_DIRECTORY, S_IRWXU | S_IRWXG | S_IRWXO);
        pDir = opendir(SYSTEM_PROFILE_DIRECTORY);
        if (pDir == 0)
        {
            TRACE(("%s does not exist or cannot be created\n", SYSTEM_PROFILE_DIRECTORY));
            return false;
        }
    }
    TRACE(("DvCfgProfileList::obtainSystemProfileList() MID 1 "));
    DvComUtil::printMemoryUsage();
    mpProfileList->clearSystemProfileList(); // 调用 (std::set) mProfileList.clear()
    TRACE(("DvCfgProfileList::obtainSystemProfileList() MID 2 "));
    DvComUtil::printMemoryUsage();
    struct dirent *pEntry;
    while ((pEntry = readdir(pDir)) != 0)
    {
        if (!strcmp(pEntry->d_name, ".") || !strcmp(pEntry->d_name, ".."))
            continue;
        TRACE(("Profile name = %s\n", pEntry->d_name));
        mpProfileList->addSystemProfile(std::string(pEntry->d_name));
    }
    closedir(pDir);
    printf("DvCfgProfileList::obtainSystemProfileList POST ");
    DvComUtil::printMemoryUsage();
    return true;
}
/* static */ void
DvComUtil::printMemoryUsage()
{
    char fname[256], line[256];
    sprintf(fname, "/proc/%d/statm", getpid());
    FILE *pFile = fopen(fname, "r");
    if (!pFile)
        return;
    fgets(line, 255, pFile);
    fclose(pFile);
    printf("MEMORY USAGE: %s", line);
}

0