c++ - 如何在 Linux(和 OSX)上查询分配的内存量?

标签 c++ c linux macos memory

虽然这可能看起来像是其他问题的重复,但让我解释一下为什么不是。

当达到某个内存限制时,我希望让我的应用程序的特定部分优雅地降级。我可以使用基于剩余可用物理内存的标准,但这并不安全,因为操作系统可能会在达到标准之前开始分页出我的应用程序使用的内存,这会认为还有一些物理内存剩余,并保持分配等。出于同样的原因,我不能使用进程当前使用的物理内存量,因为一旦操作系统开始将我换出,我将继续分配为操作系统页面内存,因此数量会不再成长。

出于这个原因,我根据我的应用程序分配的内存量选择了一个标准,即非常接近虚拟内存大小。

这个问题 (How to determine CPU and memory consumption from inside a process?) 提供了查询当前进程使用的虚拟内存量的好方法,我认为这是我需要的。

在 Windows 上,我使用 GetProcessMemoryInfo()PrivateUsage 字段,效果很好。

在 Linux 上,我尝试了几种不起作用的方法(如下所列)。虚拟内存使用对我不起作用的原因是因为在 Linux 上的 NVidia 硬件上创建 OpenCL 上下文时发生了一些事情。驱动程序保留了一个足够大的虚拟内存空间区域,以容纳所有 RAM、所有交换区和所有视频内存。我的猜测是它是为了统一地址空间和一切。但这也意味着进程报告使用了大量内存。例如,在我的系统上,top 将在 VIRT 列中报告 23.3 Gb(12 Gb 的 RAM、6 Gb 的交换、2 Gb 的视频内存,这为 NVidia 驱动程序保留了 20 Gb)。

在 OSX 上,通过使用 task_info()virtual_size 字段,我也得到了比预期更大的数字(对于在 Windows 上甚至不接近 1 Gb 的应用程序来说,几 Gb),但没有 Linux 大。

所以这里有一个大问题:我怎样才能获得我的应用程序分配的内存量?我知道这是一个有点模糊的问题(“分配的内存”是什么意思?),但我很灵活:

  • 我更愿意包含应用程序静态数据、代码部分和所有内容,但我可以没有。
  • 我更愿意包括为堆栈分配的内存,但我可以没有。
  • 我更愿意包括共享库使用的内存,但我可以没有。
  • 我真的不关心 mmap 的东西,我可以做或不做。

  • 真正重要的是,数字随着动态分配(new、malloc、任何东西)而增长,并在释放内存时缩小(我知道这可能取决于实现)。

    我尝试过的事情

    以下是我尝试和/或想到的几个解决方案,但对我不起作用。
  • 从/proc/self/status 读取

    这是 how-to-determine-cpu-and-memory-consumption-from-inside-a-process 建议的方法。但是,如上所述,这会返回虚拟内存量,这对我不起作用。
  • 从/proc/self/statm 读取

    稍微差一点:根据 http://kernelnewbies.kernelnewbies.narkive.com/iG9xCmwB/proc-pid-statm-doesnt-match-with-status ,它指的是 Linux 内核代码,这两个值之间的唯一区别是第二个值没有减去 reserved_vm 虚拟内存量。我希望 reserved_vm 将包含 OpenCL 驱动程序保留的内存,但事实并非如此。
  • 使用 mallinfo()uordblks 字段

    这似乎不包括所有分配(我猜 new s 丢失了),因为对于虚拟内存空间的 +2Gb 增长(在做了一些内存繁重的工作并仍然持有内存之后),我只是看到 mallinfo() 返回的数字增长了大约 0.1Gb。
  • 从/proc/self/smaps 读取 [heap] 部分大小

    这个值从大约 336,760 Kb 开始,在虚拟内存空间增加 +2Gb 的工作中达到峰值 1,019,496 Kb,然后它永远不会下降,所以我不确定我真的不能依赖这个数字......
  • 监控我的应用程序中的所有内存分配

    是的,在理想的世界中,我可以控制分配内存的每个人。然而,这是一个遗留应用程序,使用大量不同的分配器,一些 malloc s,一些 new s,一些特定于操作系统的例程等。有一些插件可以为所欲为,它们可以用不同的方式编译编译器等。所以虽然这对于真正控制内存会很好,但这在我的上下文中不起作用。
  • 读取OpenCL上下文初始化前后的虚拟内存大小

    虽然这可能是解决问题的“hacky”方式(我可能不得不回退到它),但我真的希望有一种更可靠的方式来查询内存,因为 OpenCL 上下文可以在我无法控制的某个地方初始化,并且其他类似但非 OpenCL 的特定问题可能会蔓延,我不知道。

  • 所以这几乎就是我所拥有的。还有一件事我还没有尝试过,因为它只适用于 OSX,但它是使用 Why does mstats and malloc_zone_statistics not show recovered memory after free? 中描述的方法,即使用 malloc_get_all_zones()malloc_zone_statistics() ,但我认为这可能与 mallinfo() 相同的问题,即不采取所有分配都考虑在内。

    那么,任何人都可以建议一种方法来查询 Linux 中给定进程的内存使用情况(这个术语很模糊,请参见上文以了解精度)(以及 OSX,即使它是一种不同的方法)?

    最佳答案

    您可以尝试使用 getrusage() 返回的信息:

    #include <sys/time.h>
    #include <sys/resource.h>
    
    int getrusage(int who, struct rusage *usage);
    
    struct rusage {
        struct timeval ru_utime; /* user CPU time used */
        struct timeval ru_stime; /* system CPU time used */
        long   ru_maxrss;        /* maximum resident set size */
        long   ru_ixrss;         /* integral shared memory size */
        long   ru_idrss;         /* integral unshared data size */
        long   ru_isrss;         /* integral unshared stack size */
        long   ru_minflt;        /* page reclaims (soft page faults) */
        long   ru_majflt;        /* page faults (hard page faults) */
        long   ru_nswap;         /* swaps */
        long   ru_inblock;       /* block input operations */
        long   ru_oublock;       /* block output operations */
        long   ru_msgsnd;        /* IPC messages sent */
        long   ru_msgrcv;        /* IPC messages received */
        long   ru_nsignals;      /* signals received */
        long   ru_nvcsw;         /* voluntary context switches */
        long   ru_nivcsw;        /* involuntary context switches */
    };
    

    如果内存信息不适合您的目的,观察页面错误计数可以帮助监控内存压力,这是您打算检测的。

    关于c++ - 如何在 Linux(和 OSX)上查询分配的内存量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38490320/

    相关文章:

    c - 在 C 中用 GtkTreeView 打印窗口?

    c++ - 将 const char* 从 std::string 传递到 Lua 堆栈变成 null

    c++ - move 语义 std::move

    c++ - 功能模板的默认参数不起作用

    使用系统调用创建新文件

    c++ - GCC在被杀死时创建带有随机后缀的目标文件

    linux - 在 linux bash 脚本中杀死一个 10 分钟的老僵尸进程

    android - linux eclipse...R 无法解析

    linux - 如何remove()内核空间中的文件?

    c++ - 在类中调用类