试验C - 为什么我不能分配和使用2GB的内存?

Jua*_*ett 5 c windows malloc

我继续尝试C.我有这个程序,可以让你决定你想吃多少RAM.

char * eatRAM()
{
    unsigned long long toEat;
    unsigned long long i = 0;
    float input;
    char * pMemory = NULL;
    int megaByte = 1048576;

    puts("How much RAM do you want to eat? (in Mega Bytes)");
    puts("NOTE: If you want to eat more RAM than you have available\nin your system, the program will crash");
    printf("\n>> MB: ");
    scanf("%f", &input);

    toEat = (unsigned long long)(input * megaByte);
    pMemory = malloc(toEat);

    printf("\n\nEating in total: %llu Bytes\n", toEat);
    puts("Check your task manager!\n");

    if(pMemory != NULL)
    {
        printf("\n\nEating in total: %llu Bytes\n", toEat);
        puts("Check your task manager!\n");

        for(i; i < toEat; i++)
        {
            pMemory[i] = 'x';
        }
    }
    else
    {
        puts("\nSeems like that amount of memory couldn't be allocated :( \n");
    }
    return pMemory;
}
Run Code Online (Sandbox Code Playgroud)

更新的问题:

问题是......如果我输入例如1024MB它可以工作,我可以在任务管理器中看到它使用1GB的RAM.即使我输入1500MB它也有效..

但如果我输入2048MB,它说

似乎无法分配内存量:(

或者即使我输入1756MB

记住我是C的新手,也许我省略了一些与操作系统允许我访问内存有关的重要内容,它可能是什么?

Han*_*ant 6

Windows上的32位进程默认情况下具有2 GB的可用地址空间.完整pow(2,32)地址空间的下半部分,操作系统使用前2 GB.由于几乎没有人使用32位操作系统,因此当您将程序与/ LARGEADDRESSAWARE链接时,可以获得4 GB.

需要由代码和数据共享2 GB VM空间.您的程序通常加载0x00400000,您使用的任何操作系统DLL(如kernel32.dll和ntdll.dll)都具有高负载地址(超过0x7F000000).至少启动线程的堆栈和默认进程堆是在程序开始运行之前创建的,它们的地址通常是不可预测的.

在大多数操作系统安装中,您的程序将受到收缩包装病毒攻击,您将注入DLL,提供反恶意软件和云存储等"服务".这些DLL的加载地址是不可预测的.您自己链接的任何DLL都会在程序启动时隐式加载.很少有程序员注意他们喜欢的基址,并将其保留为默认值0x1000000.您可以从调试器的"模块"窗口中看到这些DLL.这样的DLL通常有自己的CRT,并倾向于创建自己的堆.

您自己进行的分配,尤其是不会来自低碎片堆的非常大的分配,需要在现有代码和数据分配之间的孔中找到地址空间.如果你得到1500 MB,那么你的VM非常干净.一般情况下,你会遇到超过650 MB的麻烦,当程序运行一段时间并且虚拟机空间分散时,会迅速减少.分配失败几乎总是因为操作系统无法找到足够大的漏洞,而不是因为您没有足够的虚拟机.漏洞的总和可能比失败的分配请求大得多.

这些细节正在迅速成为一个民间故事,仍有很少的原因仍然针对x86.目标x64和地址空间碎片在接下来的20年内不会成为问题,非常难以分割8TB的VM.有很多空间可以超越这个.

所以很明显为什么你不能得到2048 MB,你无法得到它.从SysInternals的VMMap实用程序中获取进一步的信息,它向您展示了如何分割VM.Mark Russinovich的博客文章和书籍提供了很多背景资料.