我正在构建一个照片书布局应用程序。该应用程序经常将JPEG图像解压缩为内存位图缓冲区。这些图像的大小被限制在100兆像素(通常不超过15兆像素)。
有时候,这些缓冲区的内存分配会失败:
我对Mac OS X中的虚拟内存系统的理解是,在64位进程中进行的分配从理论上来说是不会失败的。有16艾字节的地址空间,我每次尝试最多分配400兆字节。理论上,我可以分配400亿个这样的缓冲区,而不会达到可用地址空间的硬限制。当然,实际限制会阻止这种情况的发生,因为交换空间受引导卷大小的限制。实际上,我只做了很少量的这些分配(不到十个)。
我不理解的是,即使在物理内存非常低的情况下,分配仍然会失败。我认为,只要还有交换空间,内存分配就不会失败(因为这些页面甚至没有映射到此时点)。
该应用程序是垃圾收集的。
编辑:
我有时间进一步研究了这个问题,以下是我的发现:
有时候,这些缓冲区的内存分配会失败:
[[NSMutableData alloc] initWithLength:]
返回nil
。这似乎发生在系统空闲物理内存接近零的情况下。我对Mac OS X中的虚拟内存系统的理解是,在64位进程中进行的分配从理论上来说是不会失败的。有16艾字节的地址空间,我每次尝试最多分配400兆字节。理论上,我可以分配400亿个这样的缓冲区,而不会达到可用地址空间的硬限制。当然,实际限制会阻止这种情况的发生,因为交换空间受引导卷大小的限制。实际上,我只做了很少量的这些分配(不到十个)。
我不理解的是,即使在物理内存非常低的情况下,分配仍然会失败。我认为,只要还有交换空间,内存分配就不会失败(因为这些页面甚至没有映射到此时点)。
该应用程序是垃圾收集的。
编辑:
我有时间进一步研究了这个问题,以下是我的发现:
- 这个问题只会出现在垃圾回收的进程中。
- 当从
NSMutableData
分配失败时,使用普通的malloc
仍然可以成功分配相同数量的内存。 - 当整体物理内存接近零(即将开始交换)时,错误总是发生。
我猜NSData
在垃圾回收下运行时使用NSAllocateCollectable
来执行分配,而不是malloc
。
我的结论是,当物理内存较低时,收集器无法分配大块内存。我对此还是不太理解。