我正在处理非常大的数据集。我正在尝试在一个单一阵列中分配16GB
出于某种原因,我不知道,如果我试图访问位置(比方说)"6亿",我会发现这个位置不可访问,并且在运行时出现分段错误。
有人知道为什么会发生这种事吗?
我的体系结构是64位的,因此应该可以寻址160亿个地址,或者至少我是这么认为的。
我的电话是:
int* array = (int*) malloc(sizeof(int)* 1000000000 * 4);
谢谢大家!
@ScottChamberlain,@Sanhdirir:它无声地失败了,因为它没有返回空指针。正如您可能已经注意到的,这个数组表示一个矩阵。在以这种方式分配它之前,我尝试用一个指向指针的指针来分配它。这需要更多的内存空间(80亿字节)来保存每个指针的地址。通过这种方式,我杀死了我的程序,而现在我没有,但当我试图访问一些地址时,我会出现分段错误。
edit如果我分配了1.6亿(甚至更多)的10个块,我不会得到任何错误,并且内存已分配。问题在于分配一个大块。我现在的问题是:有没有办法克服这个限制?
edit2@Sanhadrin你的假设都是正确的,除了我使用gcc这一事实。我在这里报告/proc/meminfo/文件的内容
MemTotal: 198049828 kB
MemFree: 113419800 kB
Buffers: 153064 kB
Cached: 5689680 kB
SwapCached: 124780 kB
Active: 73880720 kB
Inactive: 8998084 kB
Active(anon): 70843644 kB
Inactive(anon): 6192548 kB
Active(file): 3037076 kB
Inactive(file): 2805536 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 201273340 kB
SwapFree: 164734524 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 76915376 kB
Mapped: 16376 kB
Shmem: 72 kB
Slab: 190352 kB
SReclaimable: 124660 kB
SUnreclaim: 65692 kB
KernelStack: 3432 kB
PageTables: 259828 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 300298252 kB
Committed_AS: 160461824 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 733424 kB
VmallocChunk: 34258351392 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 195520 kB
DirectMap2M: 37507072 kB
DirectMap1G: 163577856 kB
信息量确实让这个问题很难回答,但看起来:
- 您使用的是x86-64体系结构
- 您可能正在运行Linux
- 你至少有16GB的RAM,但不确定你是否有超过16GB的空闲RAM
- 您正在使用gcc进行编译,其设置配置为创建64位二进制文件
- 您对malloc()的调用返回了一个看似有效(非null)的指针
- 索引到该内存可能会导致分段错误
如果你阅读malloc的手册页,上面写着:
票据
默认情况下,Linux遵循乐观的内存分配策略。这意味着当malloc()返回非NULL时,不能保证内存真的可用。如果系统内存不足,一个或多个进程将被OOM杀手杀死。有关更多信息,请参阅proc(5)中/proc/sys/vm/overcommit_memory和/proc/sys/vm/oom_adj的描述,以及Linux内核源文件Documentation/vm/overommit accounting。
通过阅读man proc,它指出:
/proc/sys/vm/overcommit_memory此文件包含内核虚拟内存记帐模式。值为:
0: heuristic overcommit (this is the default)
1: always overcommit, never check
2: always check, never overcommit
In mode 0, calls of mmap(2) with MAP_NORESERVE are not
checked, and the default check is very weak, leading to the
risk of getting a process "OOM-killed". Under Linux 2.4, any
nonzero value implies mode 1.
因此,根据overcommit_memory的设置,malloc()可能会返回一个有效的指针,即使在请求的空间不可用的情况下也是如此,因为当你使用那么多内存时,其他进程将被终止,从而释放出所需的空间。这里的情况并非如此,因为你会立即使用它——这意味着你实际上一开始就没有16GB的可用空间。进一步:
In mode 2 (available since Linux 2.6), the total virtual address space that can be allocated (CommitLimit in /proc/meminfo) is calculated as
CommitLimit = (total_RAM - total_huge_TLB) *
overcommit_ratio / 100 + total_swap
where:
* total_RAM is the total amount of RAM on the system;
* total_huge_TLB is the amount of memory set aside for
huge pages;
* overcommit_ratio is the value in
/proc/sys/vm/overcommit_ratio; and
* total_swap is the amount of swap space.
For example, on a system with 16GB of physical RAM, 16GB of
swap, no space dedicated to huge pages, and an
overcommit_ratio of 50, this formula yields a CommitLimit of
24GB.
Since Linux 3.14, if the value in
/proc/sys/vm/overcommit_kbytes is nonzero, then CommitLimit is
instead calculated as:
CommitLimit = overcommit_kbytes + total_swap
因此,至少,你可以更好地防止它过度投入,这样malloc()就会像预期的那样失败——但潜在的问题是,你要求的空间非常大,而你似乎没有。您可以检查/proc/meminfo来查看任何时候实际有多少空闲,以及其他内存统计信息,以了解问题所在以及您的实际限制。
如果您需要分配非常大的内存块,您应该使用操作系统服务将虚拟内存映射到进程;而不是malloc()。
如果你有任何希望在你的系统上分配16GB,你需要这样做。