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


69

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

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


13
这样做是没有意义的。在所有现代OS上,一个应用程序使用的内存都是虚拟的,因此不会影响其他应用程序可用的内存。仅分配您的需求。
马丁·约克2010年

9
@LokiAstari:当然是错误的。一个系统只能分配这么多。我选择没有交换文件,因此我的系统具有8GiB,此后,C ++调用new引发bad_alloc并且其他应用程序失败。在Linux和最近的Windows中,有一个OOM Killer,它将选择要杀死的应用程序。病毒可以在多个进程中分配大量资源,并利用该事实使其他应用程序崩溃。更不用说,如果您有页面文件,系统将破坏并冻结至无法使用。(通常WM只死掉,但是在Windows上没有Ctrl-Alt-F1)
v.oddou 2014年

1
@ v.oddou:这些都与问题的背景无关。因此,我的评论是正确的。
马丁·约克

2
@ v.oddou Linux OOM杀手实际上可以很快杀死虚构病毒。运行时间短,CPU使用率低,内存使用率高,许多子进程。这种无用的病毒基本上会在它的胸部以及孩子的胸部上画一个大的红叉。
yyny

2
@Loki Astari并非每个人都出于相同的原因在这里,因此编写一个垃圾收集器在内存不足时会更频繁地收集它是非常有用的。
yyny

Answers:


16

阅读完这些答案后,我感到惊讶的是,有这么多人以为OP的计算机内存属于他人。这是他的电脑,他的记忆做,因为他认为合适的,即使它伤了其他系统采取了要求它。这是一个有趣的问题。在一个更原始的系统上,我memavail()会告诉我这一点。在不破坏其他系统的情况下,OP为什么不占用他想要的内存?

这是一种分配少于一半可用内存的解决方案。输出为:

必填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
在Linux上,您可以使用binutilsfree命令(或者它是bash命令?也许),您可以使用execve或启动system。一种有趣的方法也可以尝试分配(并写入1),直到无法检测到可用内存为止。更不用说检查速度,以便检测到交换。
v.oddou 2014年

27
这是一个极其可怕的解决方案。想象一下,您正在计算机上工作,突然它开始交换并减慢了爬网速度,并且某些应用程序由于内存不足而失败,并且网络连接失败,等等。并发现这是由某些愚蠢的应用程序引起的,它们只是不断分配和释放它甚至不需要的大量内存。
迈克尔

2
试图malloc()确定可用内存是解决问题的一种糟糕方法。远非最佳和可用...。是什么使您无法使用sysctl()一系列功能,而无法从OS可调参数获得一些读数?同样,可用内存的概念因操作系统而异,例如,FreeBSD和AFAIK OS X都将闲置内存视为浪费,并将内存用于一些有用的东西(答案超出范围)这个主题)。看看这个freebsd.org/cgi/man.cgi?query=sysctl&sektion=3
fnisi

1
@FehmiNoyan我同意它不是很好,但是Windows API没有任何sysctl功能族(如果我错了,请纠正我)。在Borland Turbo C的早期memavail,有,但MSVC似乎没有。在另一个广为接受的答案GlobalMemoryStatusEx中提出了建议,但是用MSVC编译的程序无论如何只能允许程序大约2Gb的内存。我的系统有8Gb。这将如何影响其他程序?但是,如果我需要它,而其他应用程序正在阻止我按自己的意愿做事,请在自己的PC上关闭它们。
风向标

1
使用虚拟内存,可以分配比实际物理可用更多的虚拟内存。malloc()可能告诉您您拥有该内存,但是每个虚拟页面仅在您实际使用该内存时才分配给它一个物理页面(触发页面错误异常,操作系统通过分配一个空闲页面来处理该异常;可能交换一些内容)或转储缓存以释放页面)。因此,您可能会发现,如果尝试实际使用分配的所有内存,则将开始崩溃甚至被杀死,或者导致其他内容被操作系统杀死。
jtchitty

160

在类似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,您就会很高兴。


11
它不是我要用完所有内存,也不是我想去加载太多我无法使用可用内存处理的数据(我想保留在未使用的空间或可能不会出现的空间中)被其他进程访问)。同样,我不希望是愚蠢的要分配所有可用内存,但要决定我应该放什么限制应用所以它不吸了所有的记忆,并获得坠毁〜___〜
theCakeCoder

1
对于某些操作系统,sysctl可能是的更好替代方案sysconf。请参阅man 3 sysctl
Paul R

3
这对于与我有切向相关的任务很有用:当用户使用大量物理内存时向用户发出警告。我知道我可以使用更多的资源并管理虚拟内存,但是如果我使用的物理RAM数量超过了我希望能够向用户发出警告,因为这将导致速度变慢,因为这将导致分页发生。
克里斯·威斯汀

4
次要nitpick:status.ullTotalPhys是一个unsigned long long;如果该方法的返回类型很长,那么在某些系统上,您将获得无意义的结果。按原样运行代码会-729088在我的系统上产生返回值,但是将其更改为与ullTotalPhys的类型相匹配则会得到正确的返回值21474107392
放映时间2012年

3
值得一提的是,_SC_PHYS_PAGES不是在POSIX规范的一部分。
Craig Barnes

32

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


它不是完全科学的软件,我不是建立一个ETL框架,而是我打算在专用服务器上运行。可能需要保留最大允许的内存,例如Java或Maltab作为启动参数。
theCakeCoder 2014年

2
至少有理由使用渲染软件执行此操作。您想使用尽可能多的内存。例如:可用的物理内存(xα,0.5 <α<0.8)将限制光子贴图的大小。+min(physi, 2GiB)避免使用具有256GB RAM的计算机永久构建光子图。但还是。您也可以想象在游戏中漫游,我已经看到引擎通过流输入和输出资产来维持内存目标。您拥有的内存越多,您可以看到的越远。
v.oddou 2014年

14

没有平台独立的方法可以执行此操作,不同的操作系统使用不同的内存管理策略。

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

但是,您应该注意:为Linux中的可用内存获取“真实”值是非常困难的。操作系统显示的进程使用的内容不能保证为该进程实际分配的内容。

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


linux使用延迟分配,您可以通过写入来保证分配内存。
v.oddou 2014年

7

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

#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的操作系统上工作吗?)


4
这将返回系统中的总物理内存,而不是可用(空闲)内存。
紫罗兰色长颈鹿

5

下面的代码提供了总内存和可用内存(以兆字节为单位)。适用于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

3

造成这种情况的“官方”的功能就是std::get_temporary_buffer()。但是,您可能需要测试您的平台是否具有良好的实现。我了解并非所有平台的行为都符合预期。


2
此函数在C ++ 17中已弃用,并已从C ++ 20中删除。
伊莱亚斯


1

无需尝试猜测,您是否考虑过让用户配置要用于缓冲区的内存量,并假设有些保守的默认值?这样,您仍然可以无覆盖运行(可能稍慢),但是如果用户知道该应用有X内存可用,他们可以通过配置该数量来提高性能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.