c - 内存泄漏检测应该使用vsize、size和rss中的哪一个?

标签 c memory rss size

vsizesizerss 这三个值中的哪一个来自 ps输出是否适合用于快速内存泄漏检测?就我的目的而言,如果一个进程已经运行了几天并且它的内存一直在增加,那么这就足以表明它正在泄漏内存。我知道最终应该使用像 valgrind 这样的工具,但它的使用是侵入性的,因此并不总是可取的。

根据我的理解,我编写了一段简单的 C 代码,基本上分配了 1 MiB 的内存,释放它,然后再次分配 1 MiB。它还会在每一步前休眠 10 秒,让我有时间查看 ps -p <pid> -ovsize=,size=,rss= 的输出.在这里:

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>

#define info(args...) printf(args)

char* bytes(char* str, uint32_t size, uint32_t n)
{
    char* unit = "B";

    if (n > 1000) {
        n /= 1000;
        unit = "KB";
    }
    if (n > 1000) {
        n /= 1000;
        unit = "MB";
    }

    snprintf(str, size, "%u %s", n, unit);
    return(str);
}

void* xmalloc(size_t size)
{
    char msg[64];
    size_t max = sizeof(msg);
    void *p = NULL;

    info("Allocating %s\n", bytes(msg, max, size));
    p = malloc(size);
    memset(p, '1', size);
    return(p);
}


void* xfree(void* p, size_t size)
{
    char msg[64];
    size_t max = sizeof(msg);
    info("Freeing %s\n", bytes(msg, max, size));
    free(p);
    return(NULL);
}
void nap()
{
    const int dur = 10;
    info("Sleeping for %d seconds\n", dur);
    sleep(dur);
}

int main(void)
{
    int err = 0;
    size_t kb = 1024;
    size_t block = 1024 * kb;
    char* p = NULL;

    nap();
    p = xmalloc(block);
    nap();
    p = xfree(p, block);
    nap();
    p = xmalloc(block);
    nap();

    return(err);
}

现在,ps每两秒从一个 shell 脚本运行一次,该脚本还有助于打印测量时间戳。它的输出是:

# time vsize size rss
1429207116   3940   188   312
1429207118   3940   188   312
1429207120   3940   188   312
1429207122   3940   188   312
1429207124   3940   188   312
1429207126   4968  1216  1364
1429207128   4968  1216  1364
1429207130   4968  1216  1364
1429207132   4968  1216  1364
1429207135   4968  1216  1364
1429207137   3940   188   488
1429207139   3940   188   488
1429207141   3940   188   488
1429207143   3940   188   488
1429207145   5096  1344  1276
1429207147   5096  1344  1276
1429207149   5096  1344  1276
1429207151   5096  1344  1276
1429207153   5096  1344  1276

根据上面的值,并牢记 ps(1) 的手册页中给出的描述,在我看来最好的衡量标准是 vsize。这种理解是否正确?请注意,手册页说 size 是脏页总数的度量,而 rss 是物理内存中的页数。这些可能会大大低于进程使用的总内存。

这些实验是在运行 GNU/Linux 3.2.0-4-amd64 的 Debian 7.8 上进行的。

最佳答案

一般来说,进程的总虚拟大小 (vsize) 是衡量进程大小的主要指标。 rss 只是此时恰好在使用真实内存的部分。 size 衡量实际修改了多少页。

不断增加的 vsize,具有相对稳定或循环的 sizerss 值可能表明堆碎片或糟糕的堆分配器算法。

不断增加的 vsizesize 以及相对稳定的 rss 可能表明存在内存泄漏、堆碎片或糟糕的堆分配器算法。

您必须了解给定程序如何使用内存资源,以便仅使用这些进程资源使用的外部度量来估计它是否遭受内存泄漏。

其中一部分涉及了解 C 库 malloc()free() 例程如何管理堆,包括它可能需要的额外内存require 在内部管理事件分配列表,它如何处理堆碎片,以及它如何将未使用的堆部分释放回操作系统。

例如,您的测试表明,进程的总虚拟大小及其所需的“脏”页数在程序第二次再次分配相同数量的内存时略有增加。这可能显示了 malloc() 的一些开销,即到那时它自己的内部数据结构所需的内存量。如果程序在退出前执行了另一个 free()sleep() ,看看会发生什么会很有趣。修改您的代码,使其在调用 malloc()memset() 之间调用 sleep(),然后观察ps 的结果。

因此,一个简单的程序应该只需要固定数量的内存来运行,或者分配内存来完成特定的工作单元,然后在该工作单元完成后释放所有内存,应该显示相对稳定的 vsize,假设它一次处理的工作不超过一个单元,并且具有会导致堆碎片的“错误”分配模式。

正如您所指出的,像 valgrind 这样的工具,以及对程序内部实现的深入了解,对于显示实际的内存泄漏并证明它们完全是程序的责任是必要的。

(顺便说一句,您可能希望稍微简化您的代码——尤其不要使用不必要的宏,例如 info(),并且对于这种类型的示例,尝试在中打印值更大的单位,使用额外的变量来进行大小计算等,也更多的是混淆而不是帮助。太多的 printfs 也会混淆代码——只使用那些你需要查看程序在哪一步和查看值在编译时是未知的。)

关于c - 内存泄漏检测应该使用vsize、size和rss中的哪一个?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29684046/

相关文章:

c - 将硬编码写入 RAM 的特定物理地址

c++ - 保留指针地址(用作特殊情况)

html - 覆盖 rss 提要条目的图像大小

.NET ServiceModel.Syndication - 更改 RSS 源的编码

c - connect() 后的 UDP 发送行为

c++ - 当 C++ 实现向 C 代码抛出异常时会发生什么

C sscanf() 强制数字输入

c++ - 将 unsigned long long int 转换为 signed long long int 可能吗?

memory - CUDA 与 CuBlas 内存管理

javascript - 加载 React Native 后渲染 RSS 提要数据