【问题标题】:How does NSMutableData allocate memory?NSMutableData 如何分配内存?
【发布时间】:2010-08-02 11:03:51
【问题描述】:

当我运行以下代码时,它会慢慢消耗我的内存,甚至开始使用交换:

 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”中,我只看到了关于这些主题的模糊句子。

【问题讨论】:

    标签: objective-c memory-management error-handling


    【解决方案1】:

    这不是 NSMutableData 问题,而是内核/操作系统问题。如果进程请求(大)内存块,内核通常只会说“没关系,给你”。但只有在实际使用它时,它才真正(“物理地”)分配。这没关系,因为如果您的程序以 2 GB malloc 开始(就像您在此处所做的那样),否则它会立即推出其他程序进行交换,而实际上您通常不会立即使用 2 GB。

    当访问一个实际上并不存在于物理内存中的内存页面时,内核会从 CPU 获得一个信号。如果页面应该在那里(因为它在您的 2 GB 块内),它将被放置到位(可能来自交换),您甚至不会注意到。如果页面不应该存在(因为地址未在您的虚拟内存中分配),您将收到分段错误(SIGSEGV 或 EXC_BAD_ACCESS 类型的错误)。

    其中一个相关主题是“overcommit(ment)”,内核承诺提供比实际可用更多的内存。如果所有进程都开始使用它们承诺的内存,它可能会导致严重的问题。这取决于操作系统。

    互联网上有很多页面更好、更详细地解释了这一点;我只是想做一个简短的介绍,这样你就可以把条款放在谷歌上。

    edit 刚刚测试过,Linux 很容易答应我 4 TB 的内存,而 - 我向你保证 - 那台机器上什至没有 1 TB 的总存储空间磁盘 .您可以想象,如果不注意这一点,在构建关键任务系统时会引起一些麻烦。

    【讨论】:

    • 可以通过设置overcommit_memory 和overcommit_ratio 来改变Linux 的过度使用行为。特别是,将overcommit_memory 设置为 2 意味着它只会提交交换空间 + overcommit_ratio% 的物理内存。
    • Linux 的有趣之处在于mmap()(malloc 在表面之下所做的)带有一个标志MAP_NORESERVE,它允许过度使用行为。但是,如果您 - 像 malloc() 一样 - 不指定此标志,它仍然会过度使用。
    • 现在很清楚了。谢谢你。我进行了更多测试, [NSMutableData dataWithLength:length] 最终调用 malloc 并且 malloc 正在使用 mmap 分配内存。 [NSMutableData dataWithLength:length] 和 malloc 在调用时永远不会失败。即使用 NSIntegerMax 调用也不行。当第一次访问分配的内存时,程序稍后将失败并显示 EXC_BAD_ACCESS。
    • 我可以在我的系统上分配最多 0x7FFDAA104000 字节(140 PB)的内存,而不会在第一次访问它时失败。在这种情况下,我的系统用完了交换空间,并要求我通过显示“强制退出应用程序”对话框并说:“您的 Mac OS X 启动磁盘没有更多空间可用于应用程序内存”来终止进程。奇怪,但在这些系统上测试 malloc 的返回值似乎没有用。要么稍后在第一次访问分配的内存时失败,要么通过强制退出对话框通知用户该问题。
    猜你喜欢
    • 2012-02-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 2011-10-23
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    相关资源
    最近更新 更多