我正在尝试使用memmap=True
加载一些巨大的FITS记录表,并且得到error: [Errno 12] Cannot allocate memory
。
会话示例:
filename = '/home/sdfits/AGBT12B_221_01/AGBT12B_221_01.raw.acs.fits'
import astropy.io.fits as fits
filefits = fits.open(filename,memmap=True)
data = filefits[2].data[:50]
错误在此行:
/users/aginsbur/anaconda/lib/python2.7/site-packages/numpy/core/memmap.py(253)__new__()
--> 253 mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start)
ipdb> bytes
23718381056L
ipdb> bytes/1024**2
22619L
ipdb> start
413921280
ipdb> acc
3
我真的不知道发生了什么,但是我怀疑memmap不正确地决定要读取多少数据。 关于如何进一步调试的任何提示? 这实际上是FITS问题,还是麻木的问题?
细节:
In [15]: numpy.__version__
Out[15]: '1.7.1'
In [16]: astropy.__version__
Out[16]: '0.2.4'
In [18]: sys.maxint
Out[18]: 9223372036854775807
什么操作系统?
ulimit -v
返回什么?
OS是linux的一种风格。 不知道我的头顶还是
最容易找到的命令。
另外,正在使用蟒蛇蟒蛇/ astropy / numpy的anaconda安装,但已升级
通过点子
$ ulimit -v
无限
在2013年8月27日,星期二,下午4:02,Erik Bray [email protected]写道:
什么操作系统?
ulimit -v返回什么?
-
直接回复此电子邮件或在Gi tHub上查看它
。
亚当
cat /proc/meminfo
显示什么?
$ cat /proc/meminfo
MemTotal: 1903396 kB
MemFree: 203864 kB
Buffers: 215320 kB
Cached: 884708 kB
SwapCached: 2268 kB
Active: 492052 kB
Inactive: 954324 kB
Active(anon): 165684 kB
Inactive(anon): 181096 kB
Active(file): 326368 kB
Inactive(file): 773228 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 1048568 kB
SwapFree: 1031460 kB
Dirty: 24 kB
Writeback: 0 kB
AnonPages: 344352 kB
Mapped: 65676 kB
Shmem: 432 kB
Slab: 191348 kB
SReclaimable: 151148 kB
SUnreclaim: 40200 kB
KernelStack: 2312 kB
PageTables: 22940 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 2000264 kB
Committed_AS: 847268 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 286128 kB
VmallocChunk: 34359439336 kB
HardwareCorrupted: 0 kB
AnonHugePages: 12288 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 8188 kB
DirectMap2M: 2070528 kB
...看起来似乎很少的内存; 2 GB? r
@keflavich-您仍然看到此问题吗?
完全忘记了这一点。 MemTotal
只是总的可用物理内存。 当然,这2GB的存储空间不是很多,但这不应该成为问题。 VmallocTotal
大约有32 TB,这在这里很重要-原则上mmap应该能够使用其中的大部分。 因此,这里发生了一些可疑的事情。
啊! 我想我在这里看到了这个问题。 默认情况下,当以只读模式打开文件时,PyFITS使用MAP_PRIVATE
,以便用户仍然可以像修改整个文件到主内存一样修改数据数组。
问题是,从原则上讲,这意味着整个文件都可以被覆盖,因此mmap需要能够在出现这种情况之前提前分配足够的内存。 这就是为什么这发生在这里。 PyFITS / Astropy绝对应该抓住这种情况,并提供一个更有用的错误。
当前有两种解决方法:可以使用mode='denywrite
打开文件。 我是在不久前专门针对这种情况添加的,但很少使用。 这会用MAP_SHARED | PROT_READ
打开mmap-这意味着页面是只读的(任何修改数组的尝试都会导致异常)。 但是,如果您所需要做的只是读取数据,那么效果很好,并且不需要分配我不认为的任何交换空间。
另一种可能性是使用mode='update'
打开。 然后,对阵列的任何更改都可以直接同步回文件,如果您愿意的话,这很好,但是如果不需要,显然没有那么多。
查看手册页,似乎至少在Linux上还有一个标志,称为MAP_NORESERVE
,它将阻止它为写时复制预分配空间。 因此,如果您不需要对整个数组进行任何更改,也可以将它们写入工作。 但是,如果您最终用尽了交换空间,那么我们必须能够捕获产生的SIGSEGV。
设法直接重现了这一点-实际上,我提供的两种解决方法( mode='denywrite'
和mode='update'
可以使用。仍然会尝试看看我能对MAP_NORESERVE
做些什么,否则捕获此错误并提供更好的错误消息。
烦人: numpy.memmap
不允许调整传递给mmap
调用的标志。 尽管看了一下,它不过是ndarray
的轻子类,它处理创建带有正确标志的mmap,然后以mmap作为缓冲区调用ndarray.__new__
的工作。 它还添加了flush
方法。
完全避免使用numpy.memmap
并自己处理mmap应该足够容易。 但这仍然比我现在想做的还要多。 因此,我将通过捕获错误并建议现有的解决方法之一来解决此问题。
注意,在#7597中,我们不再使用np.memmap
,因此,如果有用的话,应该更容易使用其他标志。
由于已在https://github.com/astropy/astropy/pull/7926中合并了一种解决方法,因此现在可以将其关闭MAP_NORESERVE
在Python中不可用,因此不幸的是这不是一个解决方案。