NSMutableData如何分配内存?

4
当我运行以下代码时,它会慢慢地占用我的内存,甚至开始使用交换空间:
 long long length = 1024ull * 1024ull * 1024ull * 2ull; // 2 GB

 db = [NSMutableData dataWithLength:length];

 char *array = [db mutableBytes];

 for(long long i = 0; i < length - 1; i++) {
      array[i] = i % 256;
 }

如果我不用for循环运行它,就不会使用任何内存:
 long long length = 1024ull * 1024ull * 1024ull * 2ull;
 db = [NSMutableData dataWithLength:length];
 char *array = [db mutableBytes];
 /* for(long long i = 0; i < length - 1; i++) {
      array[i] = i % 256;
 } */

我只能得出NSMutableData仅仅是“保留”内存,当访问它时才真正“分配”内存的结论。这是如何实现的?
这是通过硬件(CPU)完成的吗?
NSMutableData有没有办法在其“保留”的内存中捕捉内存写入,然后才做“分配”?
这是否意味着调用[NSMutableData dataWithLength:length]永远不会失败?如果需要,它是否可以使用交换来分配任何大小的内存?
如果它可能失败,我的db变量将为空吗?
在苹果公司的“NSMutableData Class Reference”中,我只看到了关于这些主题的模糊句子。
1个回答

6
这不是NSMutableData的问题,而是内核/操作系统的问题。如果进程请求(大)块内存,内核通常会说“没问题,给你”。但只有在实际使用它时,它才会真正(“物理”)分配。这是可以接受的,因为如果您的程序从一开始就使用2 GB malloc(就像您在这里所做的那样),它将立即将其他程序推出到交换空间,而在实践中,您通常不会立即使用2 GB。
当访问实际上不存在于物理内存中的内存页时,内核将从CPU获得一个信号。如果该页应该在那里(因为它在您的2 GB块内),则会将其放置在那里(可能来自交换空间),您甚至不会注意到。如果该页不应该在那里(因为地址未分配在您的虚拟内存中),则会收到分段错误(SIGSEGV或EXC_BAD_ACCESS类型的错误)。
其中一个相关主题是“超额承诺”,其中内核承诺的内存比实际可用的内存多。如果所有进程开始使用其承诺的内存,则可能会引起严重问题。这取决于操作系统。
有很多网页可以更好地解释并详细说明这一点;我只想简要介绍一下,以便您可以在Google中找到相关术语。
编辑刚刚测试,Linux轻松承诺给我4 TB的内存,而-我向您保证-该机器上甚至没有1 TB的总磁盘存储空间。您可以想象,如果不加注意,这可能会在构建关键任务系统时引起一些麻烦。

1
可以通过设置overcommit_memoryovercommit_ratio来更改Linux的过度承诺行为。特别地,将overcommit_memory设置为2意味着它只会提交交换空间+物理内存的overcommit_ratio%。 - Matthew Flaschen
请参阅overcommit-accounting文档 - Matthew Flaschen
关于Linux的有趣之处在于mmap()(malloc在表面下执行)带有一个标志MAP_NORESERVE,它允许过度承诺行为。然而,如果像malloc()一样不指定此标志,则仍会过度承诺。 - mvds
现在清楚了。谢谢。我进行了更多的测试,[NSMutableData dataWithLength:length] 最终会调用 malloc,而 malloc 会使用 mmap 来分配内存。当调用 [NSMutableData dataWithLength:length] 和 malloc 时,它们从未失败过,即使使用 NSIntegerMax 也是如此。程序在第一次访问分配的内存时将会出现 EXC_BAD_ACCESS 错误。 - Gyozo Gaspar
我可以在我的系统上分配高达0x7FFDAA104000字节(140 PB)的内存,而不会在第一次访问时失败。在这种情况下,我的系统会用“强制退出应用程序”对话框显示并说:“您的Mac OS X启动磁盘没有更多可用于应用程序内存的空间”。奇怪的是,在这些系统上测试malloc的返回值似乎没有用处。它要么在第一次访问分配的内存时失败,要么用户通过强制退出对话框被通知问题。 - Gyozo Gaspar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接