如何获取可用内存 C++/g++?

How to get available memory C++/g++?

提问人:theCakeCoder 提问时间:3/25/2010 最后编辑:theCakeCoder 更新时间:1/19/2022 访问量:122820

问:

我想根据可用内存分配缓冲区。这样,当我进行处理时,内存使用率会上升,但仍保持在可用内存限制中。有没有办法获得可用内存(我不知道虚拟或物理内存状态会有什么不同吗?方法必须与平台无关,因为它将在 Windows、OS X、Linux 和 AIX 上使用。(如果可能的话,我还想为我的应用程序分配一些可用内存,在执行过程中不会改变)。

编辑:我用可配置的内存分配做到了。 我知道这不是一个好主意,因为大多数操作系统都为我们管理内存,但我的应用程序是一个 ETL 框架(打算在服务器上使用,但也在桌面上用作 Adobe indesign 的插件)。所以,我遇到了问题,因为 Windows 不会使用 swap,而是返回错误的 alloc 并且其他应用程序开始失败。正如我被教导要避免撞车一样,我只是想优雅地降级。

C++ 内存管理 跨平台

评论

13赞 Martin York 3/25/2010
这样做是没有意义的。在所有现代操作系统上,一个应用程序使用的内存不会影响其他应用程序可用的内存,因为它都是虚拟的。只分配您需要的。
9赞 v.oddou 11/20/2014
@LokiAstari:当然是假的。一个系统只能分配这么多。我选择没有交换文件,所以我的系统有 8GiB,之后,C++ 调用抛出,其他应用程序失败。在 linux 和最近的 Windows 中,有一个 OOM Killer 会选择一个应用程序来杀死。病毒可以在多个进程中分配很多东西,并利用这一事实使其他应用程序崩溃。更不用说,如果您有页面文件,系统将丢弃并冻结至无法使用。(通常 WM 只会死,但在 Windows 上没有 Ctrl-Alt-F1)newbad_alloc
1赞 Martin York 11/21/2014
@v.oddou:这些都与问题的背景无关。因此,我的评论成立。
2赞 yyny 5/28/2016
@v.oddou Linux OOM 杀手实际上会很快杀死图像病毒;正常运行时间短,CPU使用率低,内存使用率高,子进程多。这种无用的病毒基本上是在它的胸前和孩子们的胸前画一个大红十字。
2赞 yyny 5/28/2016
@Loki Astari 不是每个人都出于同样的原因来到这里,编写一个垃圾收集器是很有用的,它在内存不足时会更频繁地收集。

答:

16赞 mikelong 3/25/2010 #1

没有独立于平台的方法可以做到这一点,不同的操作系统使用不同的内存管理策略。

这些其他堆栈溢出问题将有所帮助:

不过,您应该注意:众所周知,在 linux 中很难获得可用内存的“真实”值。操作系统显示的进程使用的内容并不能保证实际为进程分配的内容。

这是开发嵌入式 Linux 系统(如路由器)时的常见问题,您希望在硬件允许的范围内进行尽可能多的缓冲。下面是一个示例的链接,该示例显示了如何在 linux(在 C 语言中)获取此信息:

评论

0赞 v.oddou 11/20/2014
Linux 使用延迟分配,您可以通过写入来保证内存的分配。
174赞 Travis Gockel 3/25/2010 #2

在类 UNIX 操作系统上,有 sysconf

#include <unistd.h>

unsigned long long getTotalSystemMemory()
{
    long pages = sysconf(_SC_PHYS_PAGES);
    long page_size = sysconf(_SC_PAGE_SIZE);
    return pages * page_size;
}

在 Windows 上,有 GlobalMemoryStatusEx

#include <windows.h>

unsigned long long getTotalSystemMemory()
{
    MEMORYSTATUSEX status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatusEx(&status);
    return status.ullTotalPhys;
}

所以只要做一些花哨的事情,你就可以开始了。#ifdef

评论

13赞 theCakeCoder 3/25/2010
这并不是说我想用完所有的内存,而是我不想去加载太多我无法用可用内存处理的数据(我想保留在未使用或一些可能不会被其他进程访问的空间中)。同样,我不想愚蠢地想要分配所有可用内存,但想决定我应该对应用程序施加什么限制,这样它就不会吸收所有内存并崩溃~___~
3赞 Chris Westin 10/14/2011
这对于我有一个切向相关的任务很有用:当用户使用大量物理内存时警告他们。我知道我可以使用更多内存并管理虚拟内存,但是如果我使用的物理 RAM 量超过物理 RAM 量,我希望能够警告用户,因为这将导致速度变慢,因为会产生分页。
5赞 Showtime 9/27/2012
小吹毛求疵:是一个;如果方法的返回类型很长,那么在某些系统上,你会得到无意义的结果。按原样运行代码会导致我的系统返回值为 ,但更改它以匹配 ullTotalPhys 的类型会导致正确的 .status.ullTotalPhysunsigned long long-72908821474107392
2赞 Travis Gockel 9/27/2012
这是一个很好的观点......我在代码中更改为,这在任何具有非分段寻址的系统上都应该没问题。longsize_t
5赞 Craig Barnes 8/9/2018
值得注意的是,这不是 POSIX 规范的一部分。_SC_PHYS_PAGES
9赞 Paul R 3/25/2010 #3

使用 sysctl 的 Mac OS X 示例():man 3 sysctl

#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/sysctl.h>

int main(void)
{
    int mib[2] = { CTL_HW, HW_MEMSIZE };
    u_int namelen = sizeof(mib) / sizeof(mib[0]);
    uint64_t size;
    size_t len = sizeof(size);

    if (sysctl(mib, namelen, &size, &len, NULL, 0) < 0)
    {
        perror("sysctl");
    }
    else
    {
        printf("HW.HW_MEMSIZE = %llu bytes\n", size);
    }
    return 0;
}

(也可以在其他类似 BSD 的操作系统上运行?

评论

6赞 Violet Giraffe 12/26/2013
这将返回系统中的总物理内存,而不是可用(可用)内存。
3赞 MSalters 3/25/2010 #4

对此的“官方”功能 .但是,您可能想测试您的平台是否具有良好的实施能力。我知道并非所有平台都按预期运行。std::get_temporary_buffer()

评论

4赞 Elias 11/7/2018
此函数在 C++17 中已弃用,并已从 C++20 中删除。
1赞 Mark B 3/25/2010 #5

您是否考虑过让用户配置用于缓冲区的内存量,以及假设一些保守的默认值,而不是试图猜测?这样一来,你仍然可以在不覆盖的情况下运行(可能稍微慢一点),但如果用户知道应用有 X 内存可用,他们可以通过配置该内存量来提高性能。

35赞 Paresh M 6/14/2013 #6

我们有理由希望在科学软件的 HPC 中执行此操作。(不包括游戏、网络、商业或嵌入式软件)。科学软件通常会通过数TB的数据来完成一次计算(或运行)(并运行数小时或数周) - 所有这些都不能存储在内存中(如果有一天你告诉我,任何PC,平板电脑或手机的标准TB都是标准,那么科学软件将需要处理PB或更多)。内存量也可以决定有意义的方法/算法的类型。用户并不总是想决定内存和方法 - 他/她还有其他事情要担心。因此,程序员应该对可用的内容(4Gb、8Gb 或 64Gb 左右)有一个很好的了解,以决定一种方法是自动工作还是选择更费力的方法。使用磁盘,但最好使用内存。并且不鼓励此类软件的用户在运行此类软件时在他们的计算机上做太多事情 - 事实上,他们经常使用专用的机器/服务器。

评论

0赞 theCakeCoder 9/20/2014
它不完全是科学软件,我比构建一个 ETL 框架更重要,当然它打算在专用服务器上运行。可能,它需要提供允许的最大内存,例如 Java 或 Maltab 作为启动参数。
2赞 v.oddou 11/20/2014
至少在渲染软件中这样做是有原因的。您希望使用尽可能多的内存。例如:可用的物理内存(×α为 0.5<α<0.8)将是光子映射大小的限制。+ 一些是为了避免具有 256GB RAM 的机器需要很长时间来构建光子图。但仍然如此。你也可以想象在游戏中漫游,我已经看到引擎流式传输 IN 和 OUT 资产来维护内存目标。你拥有的内存越多,你能看到的就越远。min(physi, 2GiB)
13赞 Weather Vane 10/30/2014 #7

通读了这些答案后,我惊讶地发现有这么多人认为OP的计算机内存属于其他人。这是他电脑和他的内存,可以按照他认为合适的方式使用,即使它破坏了其他系统。这是一个有趣的问题。在一个更原始的系统上,我会告诉我这一点。为什么 OP 不应该在不打扰其他系统的情况下占用他想要的内存?memavail()

这是一个解决方案,它分配的内存不到可用内存的一半,只是为了友善起见。输出为:

必需的 FFFFFFFF

必需的 7FFFFFFF

必需的 3FFFFFFF

分配的内存大小 = 1FFFFFFF

#include <stdio.h>
#include <stdlib.h>

#define MINREQ      0xFFF   // arbitrary minimum

int main(void)
{
    unsigned int required = (unsigned int)-1; // adapt to native uint
    char *mem = NULL; 
    while (mem == NULL) {
        printf ("Required %X\n", required);
        mem = malloc (required);
        if ((required >>= 1) < MINREQ) {
            if (mem) free (mem);
            printf ("Cannot allocate enough memory\n");
            return (1);
        }
    }

    free (mem);
    mem = malloc (required);
    if (mem == NULL) {
        printf ("Cannot enough allocate memory\n");
        return (1);
    }
    printf ("Memory size allocated = %X\n", required);
    free (mem);
    return 0;
}

评论

2赞 v.oddou 11/20/2014
在 Linux 上,您可以使用 binutils 命令(或者是 bash 命令?也许),您可以使用 或 启动。一个有趣的方法也可以尝试分配(并写入 1),直到无法检测到可用内存。更不用说检查速度以便检测到交换了。freeexecvesystem
40赞 Michael 3/26/2016
这是一个非常可怕的解决方案。想象一下,您正在一台计算机上工作,突然它开始交换并减慢到爬行速度,并且某些应用程序由于内存不足而失败,并且网络连接失败等。您担心自己有恶意软件、关机或运行防病毒软件,并发现这是由一些愚蠢的应用程序引起的,这些应用程序只是不断分配和释放它甚至不需要的大量内存。
4赞 fnisi 5/23/2016
尝试确定可用内存是解决问题的可怕方法;远非最佳和可用......是什么阻止您使用一系列函数并从操作系统可调参数中获取一些读数?此外,可用内存的概念因操作系统而异,例如,FreeBSD 和 AFAIK OS X 也认为未使用的内存是浪费的,并将内存用于一些有用的东西(这个问题的答案超出了本主题的范围)。看看这个 freebsd.org/cgi/man.cgi?query=sysctl&sektion=3malloc()sysctl()
1赞 Weather Vane 5/24/2016
@FehmiNoyan我同意它不是很优雅,但是 Windows API 没有任何功能系列(如果我错了,请纠正我)。在过去,Borland Turbo C 有 ,但 MSVC 似乎没有等价物。在另一个广受好评的答案中,提出了,但是使用 MSVC 编译的程序无论如何都只允许程序大约 2Gb 的内存。我的系统有 8Gb。这将如何影响其他程序?但是,如果我需要它,并且其他应用程序阻止我在自己的 PC 上随心所欲地做事,我会关闭它们。sysctlmemavailGlobalMemoryStatusEx
1赞 jtchitty 5/16/2017
使用虚拟内存,可以预留比实际可用的虚拟内存更多的虚拟内存。malloc() 可能会告诉你你有该内存,但每个虚拟页面只有在你实际使用该内存时才会获得分配给它的物理页面(触发页面错误异常,操作系统通过分配一个空闲页面来处理该异常;可能交换某些内容或转储缓存以为您释放页面)。因此,您可能会发现,如果您尝试实际使用您分配的所有内存,您将开始捶打,甚至被杀死或导致其他东西作系统杀死。
5赞 fnisi 5/23/2016 #8

下面的代码给出了以兆字节为单位的总内存和可用内存。适用于 FreeBSD,但您应该能够在您的平台上使用相同/相似的 sysctl 可调参数并执行相同的操作(Linux 和 OS X 至少有 sysctl)

#include <stdio.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>

int main(){
    int rc;
    u_int page_size;
    struct vmtotal vmt;
    size_t vmt_size, uint_size; 

    vmt_size = sizeof(vmt);
    uint_size = sizeof(page_size);

    rc = sysctlbyname("vm.vmtotal", &vmt, &vmt_size, NULL, 0);
    if (rc < 0){
       perror("sysctlbyname");
       return 1;
    }

    rc = sysctlbyname("vm.stats.vm.v_page_size", &page_size, &uint_size, NULL, 0);
    if (rc < 0){
       perror("sysctlbyname");
       return 1;
    }

    printf("Free memory       : %ld\n", vmt.t_free * (u_int64_t)page_size);
    printf("Available memory  : %ld\n", vmt.t_avm * (u_int64_t)page_size);

    return 0;
}

下面是程序的输出, 与我的系统上的 vmstat(8) 输出的比较。

~/code/memstats % cc memstats.c 
~/code/memstats % ./a.out 
Free memory       : 5481914368
Available memory  : 8473378816
~/code/memstats % vmstat 
 procs      memory      page                    disks     faults         cpu
 r b w     avm    fre   flt  re  pi  po    fr  sr ad0 ad1   in   sy   cs us sy id
 0 0 0   8093M  5228M   287   0   1   0   304 133   0   0  112 9597 1652  2  1 97

评论

0赞 Daniel Hill 11/20/2023
sysctl:“在 Linux 5.5 中删除,glibc 2.32。
3赞 Ciro Santilli OurBigBook.com 9/25/2019 #9

Linux 当前可用内存:sysconf(_SC_AVPHYS_PAGES) 和 get_avphys_pages()

总RAM覆盖在 https://stackoverflow.com/a/2513561/895245sysconf(_SC_PHYS_PAGES);

两者都是 POSIX 的 glibc 扩展,它们提供了当前可用的 RAM 页面总数。sysconf(_SC_AVPHYS_PAGES)get_avphys_pages()

然后,您只需将它们乘以即可获得当前的可用 RAM。sysconf(_SC_PAGE_SIZE)

最小可运行示例: C - 检查可用的可用 RAM?

1赞 Mimi 1/19/2022 #10

以下是在 Linux 平台上获取可用内存的建议:

/// Provides the available RAM memory in kibibytes (1 KiB = 1024 B) on Linux platform (Available memory in /proc/meminfo)
/// For more info about /proc/meminfo : https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/s2-proc-meminfo
long long getAvailableMemory()
{
  long long memAvailable = -1;
  std::ifstream meminfo("/proc/meminfo");
  std::string line;
  while (std::getline(meminfo, line))
  {
    if (line.find("MemAvailable:") != std::string::npos)
    {
      const std::size_t firstWhiteSpacePos = line.find_first_of(' ');
      const std::size_t firstNonWhiteSpaceChar = line.find_first_not_of(' ', firstWhiteSpacePos);
      const std::size_t nextWhiteSpace = line.find_first_of(' ', firstNonWhiteSpaceChar);
      const std::size_t numChars = nextWhiteSpace - firstNonWhiteSpaceChar;
      const std::string memAvailableStr = line.substr(firstNonWhiteSpaceChar, numChars);
      memAvailable = std::stoll(memAvailableStr);
      break;
    }
  }

  return memAvailable;
}