我在 C 中有一个 malloc,它是 26901^2*sizeof(double)
这让我想到这里最大的价值是多少?
另外,我在定义一个宏来访问这个二维数组时会有什么问题吗?
#define DN(i,j) ((int)i * ny + (int)j)
因为这似乎对我不起作用——或者我至少不确定它是否有效。我不知道如何在宏上进行全视图潜水以告诉我 A[DN(indx,jndx)] 实际在看什么。
假设一个典型的分配器,例如 glibc 使用的一个,有一些观察结果:
malloc
.malloc
通过调用mmap
来获取页面)。这是一个分配最大可能块的简单程序gcc largest_malloc_size.c -Wall -O2
(编译:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void *malloc_wrap(size_t size)
{
void *p = malloc(size);
if (p) {
printf("Allocated %zu bytes from %p to %p\n", size, p, p + size);
}
else {
printf("Failed to allocated %zu bytes\n", size);
}
return p;
}
int main()
{
size_t step = 0x1000000;
size_t size = step;
size_t best = 0;
while (step > 0)
{
void *p = malloc_wrap(size);
if (p) {
free(p);
best = size;
}
else {
step /= 0x10;
}
size += step;
}
void *p = malloc_wrap(best);
if (p) {
pause();
return 0;
}
else {
return 1;
}
}
./a.out
在我的机器上运行上面的程序 ( )Linux stanley 2.6.32-24-generic-pae #39-Ubuntu SMP Wed Jul 28 07:39:26 UTC 2010 i686 GNU/Linux
得到这个结果:
<snip>
Allocated 2919235584 bytes from 0x9763008 to 0xb7763008
Allocated 2936012800 bytes from 0x8763008 to 0xb7763008
Failed to allocated 2952790016 bytes
Failed to allocated 2953838592 bytes
Failed to allocated 2953904128 bytes
Failed to allocated 2953908224 bytes
Allocated 2936012800 bytes from 0x85ff008 to 0xb75ff008
这正好是 2800MiB 的分配。从 观察相关映射/proc/[number]/maps
:
<snip>
0804a000-0804b000 rw-p 00001000 08:07 3413394 /home/matt/anacrolix/public/stackoverflow/a.out
085ff000-b7600000 rw-p 00000000 00:00 0 [heap]
b7600000-b7621000 rw-p 00000000 00:00 0
b7621000-b7700000 ---p 00000000 00:00 0
b7764000-b7765000 rw-p 00000000 00:00 0
b7765000-b78b8000 r-xp 00000000 08:08 916041 /lib/tls/i686/cmov/libc-2.11.1.so
<snip>
bfc07000-bfc1c000 rw-p 00000000 00:00 0 [stack]
看起来堆在程序数据和代码之间的区域以及共享库映射之间已经扩展,这些映射紧贴用户/内核内存空间边界(在这个系统上显然是 3G/1G)。
这个结果表明使用 malloc 的最大可分配空间大致等于:
关于 glibc 和 Linux 实现,以下手动片段非常有趣:
Normally, malloc() allocates memory from the heap, and adjusts the size
of the heap as required, using sbrk(2). When allocating blocks of mem‐
ory larger than MMAP_THRESHOLD bytes, the glibc malloc() implementation
allocates the memory as a private anonymous mapping using mmap(2).
MMAP_THRESHOLD is 128 kB by default, but is adjustable using mal‐
lopt(3).
MAP_ANONYMOUS
The mapping is not backed by any file; its contents are initial‐
ized to zero.
This test was done on a x86 kernel. I'd expect similar results from a x86_64 kernel, albeit with vastly larger memory regions returned. Other operating systems may vary in their placement of mappings, and the handling of large malloc
s, so results could be quite considerably different.
这取决于您的 malloc 实现!
根据 Wikipedia,“自 v2.3 发布以来,GNU C 库 (glibc) 使用修改后的 ptmalloc2,它本身基于 dlmalloc v2.7.0。” dlmalloc 指的是 Doug Lea 的 malloc 实现。在这个实现中需要注意的重要一点是,大型 malloc 是通过操作系统的内存映射文件功能完成的,因此这些块实际上可以非常大,而不会出现很多寻找连续块的问题。
回答了 malloc 问题(取决于您未指定的操作系统),所以关于该定义:
#define DN(i,j) ((int)i * ny + (int)j)
不太安全,因为有人可能DN(a+b,c)
会这样做
((int)a+b * ny + (int)c)
这可能不是你想要的。所以在里面放了很多括号:
#define DN(i,j) ((int)(i) * ny + (int)(j))
看看DN(indx,jndx)
指向什么,只是printf("%d\n",DN(indx,jndx));
对 malloc 的调用中的 size 参数是 size_t 类型,它因实现而异。有关更多信息,请参阅此问题。
这让我想到这里最大的价值是多少?
26'901^2 = 723'663'801。如果你的双精度是 8 个字节,那么它小于 8GB。我认为分配那么多内存完全没有问题,而且我的应用程序通常会分配更多(在 64 位系统上)。(我见过的最大内存消耗是 420GB(在具有 640GB RAM 的 Solaris 10 numa 系统上),最大连续块约为 24GB。)
最大值很难识别,因为它依赖于平台:类似于 32 位系统,它依赖于用户空间/内核空间的拆分。就目前的情况而言,我认为首先要达到实际物理 RAM 的极限——在达到 libc 可以分配的极限之前。(而且内核不在乎,它只是经常扩展虚拟内存,甚至不考虑是否有足够的 RAM 来固定它。)
您可以要求 malloc()
的最大内存块是size_t
最大值 - 这是SIZE_MAX
来自<limits.h>
. 您可以成功请求的最大数量显然取决于操作系统和单个机器的配置。
您的宏不安全。它使用一个变量执行索引计算,该int
变量的范围只需要高达 32767。任何高于此的值都可能导致有符号溢出,从而导致未定义的行为。您可能最好将计算作为 a 进行size_t
,因为该类型必须能够保存任何有效的数组索引:
#define DN(i, j) ((size_t)(i) * ny + (size_t)(j))
i
(尽管请注意,如果您为or提供负值j
,您将获得一个远远超出范围的索引)。