Macos 在Mac OS X上,中等大小的内存分配如何在64位进程中失败?
我正在构建一个相册布局应用程序。该应用程序经常将JPEG图像解压缩到内存位图缓冲区中。图像的大小被限制为1亿像素(而它们通常不超过1500万像素) 有时这些缓冲区的内存分配失败:Macos 在Mac OS X上,中等大小的内存分配如何在64位进程中失败?,macos,64-bit,memory-management,nsdata,Macos,64 Bit,Memory Management,Nsdata,我正在构建一个相册布局应用程序。该应用程序经常将JPEG图像解压缩到内存位图缓冲区中。图像的大小被限制为1亿像素(而它们通常不超过1500万像素) 有时这些缓冲区的内存分配失败:[[NSMutableData alloc]initWithLength:返回nil。这似乎发生在系统的可用物理内存接近零的情况下 我的理解是,64位进程(sic)中的分配实际上不会失败。有16 EB的地址空间,我试图一次最多分配400 MB。理论上,我可以分配400亿个这样的缓冲区,而不会达到可用地址空间的硬限制。当然
[[NSMutableData alloc]initWithLength:
返回nil
。这似乎发生在系统的可用物理内存接近零的情况下
我的理解是,64位进程(sic)中的分配实际上不会失败。有16 EB的地址空间,我试图一次最多分配400 MB。理论上,我可以分配400亿个这样的缓冲区,而不会达到可用地址空间的硬限制。当然,实际限制会阻止这种情况,因为交换空间受到启动卷大小的限制。事实上,我只做了很少的这些分配(少于10)
我不明白的是,无论此时的物理内存有多低,分配都会失败。我认为只要有交换空间,内存分配就不会失败(因为此时页面甚至没有映射)
应用程序被垃圾收集
编辑:
我有时间进一步研究这个问题,以下是我的发现:
NSMutableData
分配失败时,普通malloc
仍能成功分配相同数量的内存NSData
使用NSAllocateCollectable
执行分配,而不是malloc
我的结论是,当物理内存不足时,收集器无法分配大块内存。同样,我也不明白。即使64位计算机理论上可以处理18EB,但当前的处理器限制在256TB。当然,你也没有达到这个极限。但您的进程一次可以使用的内存量仅限于可用的RAM量。操作系统还可能限制您可以使用的RAM数量。根据您发布的链接,“即使对于具有4 GB或更多可用RAM的计算机,系统也很少将这么多RAM用于单个进程。”
initWithBytes:length:
尝试在活动内存中分配其整个长度,基本上相当于该大小的malloc()
。如果长度超过可用内存,您将得到零。如果您想使用带有NSData
的大型文件,我建议使用initWithContentsOfMappedFile:
或类似的初始值设定项,因为它们使用VM系统在需要时将部分文件拉入和拉出活动内存。您可能会耗尽交换空间。即使您有交换文件和虚拟内存,可用交换空间的大小仍然受到交换文件硬盘空间的限制。这可能是内存碎片问题。也许在分配时没有任何400 MB的连续块可用
您可以在应用程序生命周期的一开始就尝试分配这些大数据块,以免堆被大量较小的分配分割。另一种猜测是,您同事的机器配置了更严格的每个用户进程最大内存设置。要检查,请键入
ulimit-a
进入控制台。对我来说,我得到:
~ iainmcgin$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 256
pipe size (512 bytes, -p) 1
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 266
virtual memory (kbytes, -v) unlimited
~iainmcgin$ulimit-a
核心文件大小(块,-c)0
数据段大小(千字节,-d)不受限制
文件大小(块,-f)不受限制
最大锁定内存(KB,-l)不受限制
最大内存大小(千字节,-m)不受限制
打开文件(-n)256
管道大小(512字节,-p)1
堆栈大小(千字节,-s)8192
cpu时间(秒,-t)不受限制
最大用户进程(-u)266
虚拟内存(KB,-v)不受限制
从我上面的设置来看,似乎每个进程的内存使用没有限制。出于某种原因,你的同事可能不是这样
我用的是雪豹:
~ iainmcgin$ uname -rs
Darwin 10.6.0
~iainmcgin$uname-rs
达尔文10.6.0
答案在于执行这项计划
从OS X 10.6开始,将为64位平台上的垃圾收集内存分配一个8GB的竞技场。该竞技场因分配量大(>=128k)和分配量小而被削减一半(您是否以64位模式运行操作系统?可以运行64位进程,但我认为除非操作系统也以64位模式运行,否则您无法获得64位的全部好处。我认为这可能会对您的情况产生影响。正如我在问题中试图澄清的那样,我正在使用缓冲区来解压缩图像,因此映射文件不是一个选项。关于ur声明:“如果长度超过可用内存,您将得到零。”:这正是问题所在。我对虚拟内存(与交换空间一起)的理解是,只要地址空间没有填满,分配就不会失败。非常正确,对此表示抱歉。在我的(有限的)中测试
NSData
在64位进程中分配大量GB内存从来没有遇到过问题。它在32位机器中的内存限制为2GB。无论如何,因为NSData是一个对象,它必须存在于Objective-C运行时中,该运行时分配堆上的所有对象。对于非常大的分配,您可能需要使用CFData
函数,因为它们不会产生这样的开销,并且允许您使用Mach的Copy-On-Write内存管理。您还可以检查他的系统日志,查看分配失败是否记录了应该记录的异常。Th