C++ 为什么此应用程序没有';I don’我不会消耗预期的内存

C++ 为什么此应用程序没有';I don’我不会消耗预期的内存,c++,linux,performance,memory,process,C++,Linux,Performance,Memory,Process,我编写了一个简单的应用程序来测试内存消耗。在这个测试应用程序中,我创建了四个进程来持续消耗内存,这些进程不会释放内存,除非进程退出 我预计这个测试应用程序将消耗RAM的大部分内存,并导致另一个应用程序减速或崩溃。但结果与预期不一样。代码如下: #include <stdio.h> #include <unistd.h> #include <list> #include <vector> using namespace std; uns

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

我预计这个测试应用程序将消耗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;
 }
虽然CPU很高,但内存百分比仍为0.0。怎么可能呢

  • 自由指挥

                      free  shared    buffers     cached          
    Mem:           3083796       0      55996     428296
    
    4G内存中的可用内存超过3G


  • 有人知道为什么这个测试应用程序不能按预期工作吗?

    如果你想占用大量内存:

    int mb = 0;
    char* buffer;
    while (1) {
        buffer = malloc(1024*1024);
        memset(buffer, 0, 1024*1024);
        mb++;
    }
    
    在进行一些文件I/O定时测量时,我使用类似这样的方法来确保文件缓冲区缓存为空


    正如其他答案已经提到的,您的代码在分配缓冲区后不会写入缓冲区。此处,memset用于写入缓冲区。

    要将注释转换为答案:

    • Linux不会为进程分配内存页,直到它写入内存页(写时复制)
    • 此外,您不会在任何地方写入缓冲区,因为
      无符号字符的默认构造函数
      ,而
      new[]
      默认初始化所有项
    Linux使用乐观内存分配:在实际写入某一页之前,它不会物理分配该页内存。因此,您可以分配比可用内存多得多的内存,而不会增加系统的内存消耗

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

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

    buffer = new unsigned char [TEN_MEGA];
    
    如果要强制提交,请使用零初始化:

    buffer = new unsigned char [TEN_MEGA]();
    
    fork()
    在父级中返回PID,在子级中返回0。您编写的
    ForkChild
    将在父级而不是子级中执行所有工作


    标准的
    new
    操作符永远不会返回null;如果分配内存失败,它将抛出(但由于过度分配,它实际上在Linux中也不会这样做)。这意味着您在分配后对
    缓冲区的测试是没有意义的:它将始终执行第一个分支,或者永远不会到达测试。如果希望返回空值,则需要编写
    new(std::nothrow).
    。包括
    ,使其工作。

    但是您的程序实际上正在做您期望它做的事情。正如答案所指出的(@Michael Foukarakis's),未使用的内存不会被分配。在
    top
    程序的输出中,我注意到
    virt
    列上有大量内存用于运行程序的每个进程。后来我在谷歌上搜索了一下,我看到了这是什么:

    VIRT--
    虚拟内存大小(KiB)。任务使用的虚拟内存总量。
    包括所有代码、数据和共享库,以及已调出的页面和已映射但未使用的页面。

    如您所见,您的程序实际上为自己生成了内存,但它是以页面的形式并存储为虚拟内存。我认为这样做是明智的

    这篇文章的一个片段

    内存页、或虚拟页——一个固定长度的连续虚拟内存块,它是以下各项的最小数据单元:

    • 由操作系统为程序执行的内存分配;及
    • 在主存储器和任何其他辅助存储器(如硬盘驱动器)之间进行传输
    …因此,一个程序可以寻址比计算机中实际存在的内存更多的(虚拟)RAM。虚拟内存是一种让用户产生使用大块连续内存空间(甚至可能比真实内存大)的错觉的方案,而实际上他们的大部分工作都在辅助存储器(磁盘)上。根据需要将作业的固定大小块(页)或可变大小块读入主内存

    来源


    除非您对内存页进行写入,否则Linux实际上不会分配内存页。我没有看到你在任何地方向缓冲区写东西@한국매미
    new[]
    default初始化所有项目。@CoryNelson是的,
    unsigned char
    的默认初始化是否定操作:不涉及写入。@CoryNelson@한국매미 如果你把你的评论作为对这篇文章的回答,我会接受。为什么每次分配一个MB?为什么不直接分配几百MB或GB?当然,再乘以1024。好的,我已经编辑了一点。更好?如果你仍然认为它毫无价值,告诉我,这样我就可以删除它了。@Puppy很久以前,但是你还想看到其他的变化吗?哦,我又困惑了。如果程序实际上保留了内存,为什么我通过运行“无外壳”命令(我的计算机的RAM是4G字节)得到了“免费3083796”?如果你仍然感到困惑,我已经更新了我的答案,加上我在Unix&Linux exchange网站上找到的答案,我想那里的人会更好地向你解释。是的,你是对的,在判断哪个是子进程时,我确实犯了一个错误。此外,你对新运营商的评论也让我受益匪浅。非常感谢您指出这些!非常简短和有用!如果您的评论来得更早,我可能会做出不同的决定:41;-1使用
    new
    ??这个问题不是问最佳实践,而是问内存使用情况。答案简明扼要地说明了这一点——引入任何其他东西只会让它变得错综复杂。
    buffer = new unsigned char [TEN_MEGA]();