【问题标题】:Memory allocation failed even when there is still enough memory即使仍然有足够的内存,内存分配也会失败
【发布时间】:2013-09-26 02:27:42
【问题描述】:

我正在使用 Linux(确切地说是 ubuntu 13.04),目前我有一个问题:为什么即使内存仍然足够,内存分配也会失败?

我今天写了一个简单的测试应用程序,在运行这个测试应用程序时遇到了这个问题。下面是我用来测试的代码sn-p:

     #include <stdio.h>
     #include <unistd.h>
     #include <list>
     #include <vector>
     #include <strings.h>

     using namespace std;
     unsigned short calcrc(unsigned char *ptr, int count)
     {
        unsigned short crc;
        unsigned char i;

        //high cpu-consumption code
        //implements CRC algorithm: Cylic 
        //Redundancy code              
     }


     void* CreateChild(void* param){
         vector<unsigned char*>  MemoryVector;
         pid_t PID = fork();
         if (PID == 0){
             const int MEMORY_TO_ALLOC =  1024 * 1024;
             unsigned char* buffer = NULL;
             while(1){
                 buffer  = NULL;
                 try{
                     buffer = new unsigned char [MEMORY_TO_ALLOC]();
                     calcrc(buffer, MEMORY_TO_ALLOC );
                     MemoryVector.push_back(buffer);
                 } catch(...){
                     printf("an exception was thrown!\n");
                     continue;
                 } //try ... catch
             } //while  
          } // if pid == 0

      return NULL;
      }

    int main(){
        int children = 4;
        while(--children >= 0){
            CreateChild(NULL);
        };

        while(1) sleep(3600);
        return 0;
    }

在我的测试中,当有大约 220M RAM 可用时,上面的代码开始抛出异常。从那一刻起,应用程序似乎无法再获得更多内存 因为 TOP 命令显示的空闲内存仍然在 210M 以上。那为什么会这样呢?

更新
1. 软硬件信息
RAM 为 4G,交换空间约为 9G 字节。运行“uname -a”给出:Linux steve-ThinkPad-T410 3.8.0-30-generic #44-Ubuntu SMP Thu Aug 22 20:54:42 UTC 2013 i686 i686 i686 GNU/Linux 2. 测试期间的统计数据

      Right after Test App Starts Throwing Exception
      steve@steve-ThinkPad-T410:~$ free
                    total       used       free     shared    buffers     cached
       Mem:       3989340    3763292     226048          0       2548      79728
       -/+ buffers/cache:    3681016     308324
       Swap:      9760764    9432896     327868

      10 minutes after Test App Starts Throwing Exception
      steve@steve-ThinkPad-T410:~$ free
                    total       used       free     shared    buffers     cached
       Mem:       3989340    3770808     218532          0       3420      80632
       -/+ buffers/cache:    3686756     302584
       Swap:      9760764    9436168     324596


      20 minutes after Test App Starts Throwing Exception
      steve@steve-ThinkPad-T410:~$ free
                    total       used       free     shared    buffers     cached
       Mem:       3989340    3770960     218380          0       4376     104716
       -/+ buffers/cache:    3661868     327472
       Swap:      9760764    9535700     225064

      40 minutes after Test App Starts Throwing Exception
      steve@steve-ThinkPad-T410:~$ free
                    total       used       free     shared    buffers     cached
       Mem:       3989340    3739168     250172          0       2272     139108
       -/+ buffers/cache:    3597788     391552
       Swap:      9760764    9556292     204472

【问题讨论】:

  • 使用220M时失败,还是220M空闲时失败?是32位进程吗?您是否检查过该进程是否设置了任何内存限制(ulimit 或其他什么?我不知道,我不是 linux 人)计算机有多少内存和交换?
  • @MooingDuck 在可用内存超过 210M 时失败。更新了帖子。

标签: c++ linux memory process


【解决方案1】:

您在 x86-32 上运行,因此您的进程是 32 位的。即使有更多内存 + 交换,它们也会受到地址空间的限制,运行:

grep “HIGHMEM” /boot/config-`uname -r`
grep “VMSPLIT” /boot/config-`uname -r`

看看你的内核是如何配置的。

也许您的 4 个子进程被限制为 3G,并且正在使用 12G + 其他进程 ~700M 来达到您所看到的数字。

编辑:

因此,您的内核被配置为为每个用户空间进程提供 3G 的地址空间,其中一些将被程序、库和初始运行时内存占用(由于分叉,这些内存将被共享)。

因此,您有 4 个孩子每个使用 ~3G - ~12G + ~780M 其他程序。一旦孩子们开始报告错误,这将留下大约 220M 的空闲空间。

您可以只运行另一个子进程,也可以使用 AND64/x86-64 版本的 Ubuntu 重新安装,这样每个进程都可以分配更多内存。

【讨论】:

  • 第一个是“CONFIG_HIGHMEM64G=y CONFIG_HIGHMEM=y”
  • 第二个是“CONFIG_VMSPLIT_3G=y”
  • @StevePeng 所以答案是您的子进程每个都限制为 3G。
  • 是的,你是对的。如果我在我的应用程序中创建 6 个进程,那么在它开始抛出异常后,其他应用程序会因内存不足而变慢,并且即使是“free”shell 命令也无法启动更多进程。
【解决方案2】:

在我的测试中,上面的代码在大约 220M 内存时开始抛出异常。从那一刻起,应用程序似乎无法再获得更多内存,因为 TOP 命令显示的可用内存仍然在 210M 以上。那为什么会这样呢?

top 的输出每 N 秒更新一次(已配置),并不真正显示当前状态。

另一方面,内存分配非常快。

发生的情况是您的程序占用了内存,并且在某个时刻(当 top 显示 200 Mb 空闲时)它开始失败。

【讨论】:

    【解决方案3】:

    您的地址空间中可能没有 1MB 的连续内存页。您有可用空间碎片。

    【讨论】:

    • 还有一些没有被堆使用的内存。
    • 我同意 - 很可能存在碎片。此外,还不清楚“大约有 210M 内存”是什么意思。 “记忆”在哪里?在系统中?正在进行中?在交换中?
    • @JonWatte 当系统内存超过 210M 时,测试应用开始抛出异常。我更新了帖子。
    • 这不取决于你有多少系统内存。每个 32 位进程(我想是你的情况)都有它自己的 4 Gb 地址空间。其中几乎有 2 个进程可以使用(或在某些系统上为 3 个)。仅此而已。那么,这个进程到底使用了多少内存?(我不知道如何在linux中查看)
    • 请注意,进程本身实际上可能有不到 4 GB 的可用地址空间—— 2 GB 或 3 GB 是 32 位进程的典型限制。共享库、可执行文件和线程堆栈也占用地址空间。
    猜你喜欢
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    • 1970-01-01
    • 2014-12-31
    • 1970-01-01
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多