为什么这个应用程序不会消耗尽可能多的内存

时间:2013-09-20 05:01:03

标签: c++ linux performance memory process

我写了一个简单的应用来测试内存消耗。在这个测试应用程序中,我创建了四个持续消耗内存的进程,除非进程退出,否则这些进程不会释放内存。

我希望这个测试应用程序占用大部分RAM内存并导致其他应用程序变慢或崩溃。但结果与预期不一样。以下是代码:

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

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

     //high cpu-consumption code 
     //implements the CRC algorithm
     //CRC is Cyclic Redundancy Code
 }


 void* ForkChild(void* param){
    vector<unsigned char*>  MemoryVector;
    pid_t PID = fork();
    if (PID > 0){
        const int TEN_MEGA = 10 * 10 * 1024 * 1024;
        unsigned char* buffer = NULL;
        while(1){
            buffer  = NULL;
            buffer = new unsigned char [TEN_MEGA];
            if (buffer){
                 try{
                    calcrc(buffer, TEN_MEGA);
                    MemoryVector.push_back(buffer);
                 } catch(...){
                    printf("An error was throwed, but caught by our app!\n");
                    delete [] buffer;
                    buffer = NULL;
                 }
            }
            else{
                 printf("no memory to allocate!\n");
                 try{
                     if (MemoryVector.size()){
                        buffer = MemoryVector[0];
                        calcrc(buffer, TEN_MEGA);
                        buffer = NULL;
                     } else {
                        printf("no memory ever allocated for this Process!\n");
                        continue;
                     }
                 } catch(...){
                    printf("An error was throwed -- branch 2," 
                           "but caught by our app!\n");
                    buffer = NULL;
                 }
             }
         }  //while(1)
    } else if (PID == 0){
    } else {
      perror("fork error");
    }   

    return NULL;
}


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

    while(1) sleep(1);
    printf("exiting main process\n");
    return 0;
 }
  1. TOP命令

    PID  USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND           
    2775 steve     20   0 1503m  508  312 R  99.5  0.0   1:00.46 test              
    2777 steve     20   0 1503m  508  312 R  96.9  0.0   1:00.54 test              
    2774 steve     20   0 1503m  904  708 R  96.6  0.0   0:59.92 test              
    2776 steve     20   0 1503m  508  312 R  96.2  0.0   1:00.57 test
    

    虽然CPU很高,但内存百分比仍为0.0。怎么可能?

  2. 免费命令

                      free  shared    buffers     cached          
    Mem:           3083796       0      55996     428296
    

    4G RAM中的可用内存超过3G。

  3. 有没有人知道为什么这个测试应用程序没有按预期工作?

5 个答案:

答案 0 :(得分:6)

Linux使用乐观内存分配:在实际写入该页面之前,它不会物理分配一页内存。因此,您可以分配比可用内存更多的内存,而不会增加系统的内存消耗。

如果要强制系统分配(提交)物理页面,则必须写入

以下行不会发出任何 write ,因为它是unsigned char的默认初始化,这是一个无操作:

buffer = new unsigned char [TEN_MEGA];

如果要强制提交,请使用零初始化:

buffer = new unsigned char [TEN_MEGA]();

答案 1 :(得分:3)

将评论作为答案:

  • Linux不会为进程分配内存页面,直到它写入 copy-on-write )。
  • 此外,您不是在任何地方写入缓冲区,因为unsigned char does not perform any initializations的默认构造函数和new[]默认初始化所有项目。

答案 2 :(得分:1)

fork()返回父级中的PID,并返回子级中的0。你写的ForkChild将执行父母的所有工作,而不是孩子。

标准new运算符永远不会返回null;如果它无法分配内存,它将抛出(但由于过度使用它在Linux中实际上不会这样做)。这意味着您在分配后对buffer的测试毫无意义:它将始终采用第一个分支或永远不会到达测试。如果要返回null,则需要编写new (std::nothrow) ...。包括<new>以便工作。

答案 3 :(得分:0)

但是你的程序实际上正在做你期望它做的事情。正如答案所指出的那样(@ Michael Foukarakis的answer),未分配的内存未被分配。在top程序的输出中,我注意到列virt对于运行程序的每个进程都有大量内存。稍后有点谷歌搜索,我看到了这是:

VIRT - Virtual Memory Size (KiB). The total amount of virtual memory used by the task. 它包括所有代码,数据和共享库以及已换出的网页和已映射的网页 但未使用。

正如您所看到的,您的程序实际上确实为自己生成了内存,但是以页面的形式存储并存储为虚拟内存。而且我认为这是明智之举

wiki page

的摘录

页面内存页面虚拟页面 - 一个固定长度的连续虚拟内存块,它是最小的以下数据单位:

  • 操作系统为程序执行的内存分配;和
  • 在主内存和任何其他辅助存储(例如硬盘驱动器)之间传输。

...因此,程序可以处理比计算机中实际存在的更多(虚拟)RAM。虚拟内存是一种方案,它为用户提供了处理大块连续内存空间(可能甚至比实际内存更大)的错觉,而实际上他们的大部分工作都在辅助存储(磁盘)上。根据需要,将作业的固定大小的块(页面)或可变大小的块读入主存储器。

<强>来源

答案 4 :(得分:-1)

如果你想吞噬大量的记忆:

int mb = 0;
char* buffer;
while (1) {
    buffer = malloc(1024*1024);
    memset(buffer, 0, 1024*1024);
    mb++;
}

我使用这样的东西来确保在进行一些文件I / O定时测量时文件缓冲区高速缓存是空的。

正如其他答案已经提到的那样,您的代码在分配后不会写入缓冲区。这里使用memset写入缓冲区。