C-如何malloc a块尺寸的uint_max



我想创建一个具有UINT_MAX索引数的数组。由于某种原因,这非常困难。我尝试了以下内容:

  • char arr[UINT_MAX]; // Compiler claims array size cannot be negative
  • char* const arr = calloc(UINT_MAX, sizeof(char)); // Runs but seg fault when accessed
  • char* const arr = malloc(sizeof(char) * UINT_MAX); // arr is NULL

我不明白发生了什么。这是我的堆尺寸太低吗?如果是这样,我该如何增加它?malloc/calloc不能处理这种性质的块吗?我发现在malloccalloc API页面中没有任何有用。

这个问题同时适用于C 。

Windows 7 64位,16GB RAM,CMAKE 3.6.1,GCC 7.11.1,并在Clion 64位上编译。

首先,让我们首先我指出的是,您可以应该使用errno检查为什么API调用失败。

现在,让我们检查一下您的尝试:

堆栈分配 -char arr[UINT_MAX]

您正在尝试在堆栈上分配4294967295字节,这是不可行的,因为操作系统将堆栈尺寸限制为较小的尺寸。您可以尝试使用本手册中指定的API进行操作。

malloc

在大多数情况下,堆分配将失败,原因是:操作系统无法分配足够大的连续内存。

并不是您的系统没有4GB的免费内存,而是完全不适合您请求的单个连续内存。因此,就像malloc的MSDN页面指出:

malloc返回一个空隙指针到分配的空间,如果没有足够的内存,则null

calloc

malloccalloc使用相同的基础机制,因此,如果失败,您应该期望第二个机制也会失败。请参阅calloc的MSDN页面的备注部分


关于malloc在Linux平台上的有趣事实

按照评论的请求,我将指出有关malloc在Linux上实现的一些有趣事实,因为它有很大不同!

首先,Linux专门指定其使用乐观的内存管理算法:

默认情况下,Linux遵循一个乐观的内存分配策略。这意味着,当malloc()返回非零件时,无法保证内存确实可用。如果事实证明该系统不在记忆中,那么一个或多个过程将被OOM Killer

杀死

这意味着内存实际上不是为Callee拥有和专用的,而是操作系统希望在他需要的时候可以为他提供内存,如果不是,它恢复了一些令人讨厌的手段。

edit :正如@basile starynkevitch正确指出的那样,此机制取决于内存过度的开关,默认情况下启用了, 但可以禁用。

它是特定于操作系统的。但是,不检查malloccalloc的故障会导致不确定的行为(例如,您使用calloc的SEGFAULT),并且是始终错误(并且应该避免这样做的基本错误)。请记住,malloccalloc可能会失败,并且在请求或已经使用了大量内存时更有可能失败(因为虚拟内存是有限的资源)。请注意,sizeof(char)总是1。

以下程序

 // file hatefiend.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <limits.h>
 int main(int argc, char**argv) {
   size_t sz = (argc>1)?(size_t)(atol(argv[1])):UINT_MAX;
   char *ad = malloc(sz);
   if (!ad) {perror("malloc"); exit(EXIT_FAILURE); };
   for (unsigned long ix=0; ix<(unsigned long)sz; ix += 1024)
     ad[ix] = (char)(' ' + (ix & 0x3f));
   printf ("ad=%p sz=%zdn", ad, sz);
   /// the code below is optional and Linux specific, 
   /// remove it or adapt it for Windows
   char cmd[80];
   snprintf(cmd, sizeof(cmd), "pmap %d", (int)getpid());
   printf ("command: %sn", cmd);
   fflush(NULL);
   int bad = system(cmd);
   if (bad) return  EXIT_FAILURE;
   return 0;
 }   

在我的Linux/debian/x86-64笔记本电脑系统上使用16 gbytes RAM(并且不会通过gcc -Wall -O hatefiend.c -o hatefiend优化ad,因为它在printf中使用并填充)给予:

% ./hatefiend
ad=0x7fc3d5c09010 sz=4294967295
command: pmap 31644
31644:   ./hatefiend
000056355b8e3000      4K r-x-- hatefiend
000056355bae3000      4K r---- hatefiend
000056355bae4000      4K rw--- hatefiend
000056355c3de000    132K rw---   [ anon ]
00007fc3d5c09000 4194308K rw---   [ anon ]
00007fc4d5c0a000   1612K r-x-- libc-2.24.so
00007fc4d5d9d000   2048K ----- libc-2.24.so
00007fc4d5f9d000     16K r---- libc-2.24.so
00007fc4d5fa1000      8K rw--- libc-2.24.so
00007fc4d5fa3000     16K rw---   [ anon ]
00007fc4d5fa7000    140K r-x-- ld-2.24.so
00007fc4d6190000      8K rw---   [ anon ]
00007fc4d61c7000     12K rw---   [ anon ]
00007fc4d61ca000      4K r---- ld-2.24.so
00007fc4d61cb000      4K rw--- ld-2.24.so
00007fc4d61cc000      4K rw---   [ anon ]
00007ffe8f561000    132K rw---   [ stack ]
00007ffe8f5b7000     12K r----   [ anon ]
00007ffe8f5ba000      8K r-x--   [ anon ]
 total          4198476K

您可以从PMAP的输出(1)看到内存确实分配了。

您可以轻松地适应Windows系统:删除<unistd.h>并更改snprintf以构建显示虚拟地址空间的命令,即用某些Windows特定实用程序替换pmap;或只需删除命令的所有构建,即cmd及其用法...

所以请自己帮个忙:安装和使用Linux(可以将其视为挑衅或有用的提示)。 Windows 上的malloccalloc上的可能已经失败了。或努力工作以了解为什么会发生这种情况,也许在系统中配置某些内容让巨大的malloc成功。如何做到这是一个sysadmin问题,出于堆栈溢出的范围(但是您可以询问超级用户)。当心内存过度承诺(我通常会禁用)。

我的堆尺寸太低了吗?如果是这样,我该如何增加它?

您可能想增加虚拟内存或虚拟地址空间限制(因为堆是malloc给出的)。如何做到这是一个sysadmin问题(应该在Superuser上问),您需要提供更多的详细信息才能获得帮助。

在评论中,您提到您的size_t是32位整数(这让我感到惊讶; 您是否以64位模式编译?我的linux/x86-64机器是64位,例如某些uint64_tunsigned long)。然后,我相信您想要的系统是不可能的(因为malloc实现将需要一些额外的空间-e.g。书籍保存的几个额外单词,也许在某些内部size_t中算出开销。...)


请记住,此malloc(不是很有用,但很快)遵循C标准的字母。


但是,我确实相信您有一些XY问题,否则您可以实现自己的目标(这是未说的)。这就是为什么激励问题在堆栈溢出中很重要的原因。也许将arr声明为静态变量可能会有所帮助:static char arr[UINT_MAX]; ....但还请阅读此内容。数组,但是无论如何

char arr[UINT_MAX];

这太大了,对于堆栈尺寸而言。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。您可以在使用FLAG -stack编译时增加堆栈尺寸,但仍限于您的系统配置。

您可以通过调用命令ulimit -s检查限制,然后将其设置为无限制的ulimit -s unlimited

malloc返回null,因为它不能分配您要求的内存,而对于calloc

增加您的虚拟内存或物理内存或两者都能获得此内存。即使有可用的内存,它也很可能在某种程度上分散了系统来纪念您的请求。

相关内容

  • 没有找到相关文章

最新更新