Я пытаюсь загрузить несколько гигантских таблиц записей FITS, используя memmap=True
, и получаю 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
?
ОС - это некоторая разновидность Linux; не знаю из головы или
самая простая команда, чтобы узнать.
Кроме того, использовалась установка anaconda для python / astropy / numpy, но была обновлена
астропия через пипс.
$ ulimit -v
неограниченный
27 августа 2013 г. в 16:02 Эрик Брей [email protected] написал:
Какая ОС?
Что возвращает ulimit -v?
-
Ответьте на это письмо напрямую или просмотрите его на Gi tHubhttps: //github.com/astropy/astropy/issues/1380#issuecomment -23374814
.
Адам
Что показывает 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 ГБ? Хмф.
@keflavich - вы все еще
Совсем забыл об этом. MemTotal
- это всего лишь общая доступная физическая память. Эти 2 ГБ - это немного, конечно, но это не должно быть проблемой. У вас есть около 32 ТБ на VmallocTotal
что здесь должно иметь значение - в принципе mmap должен иметь возможность использовать большую часть этого. Так что здесь происходит что-то подозрительное.
Ах! Думаю, я вижу здесь проблему. По умолчанию PyFITS использует MAP_PRIVATE
при открытии файла в режиме только для чтения, чтобы пользователи могли изменять массив данных на месте, как если бы весь файл был отображен в основную память.
Проблема в том, что в принципе это означает, что весь файл может быть перезаписан, поэтому mmap должен иметь возможность заранее выделить достаточно памяти, если это произойдет. Вот почему это происходит здесь. PyFITS / Astropy определенно должен отловить этот сценарий и предоставить более полезную ошибку.
В настоящее время есть два способа обойти это: Вы можете открыть файл с помощью mode='denywrite
. Я добавил это некоторое время назад специально для этого случая, но он используется редко. Это открывает mmap с помощью MAP_SHARED | PROT_READ
означает, что страницы доступны только для чтения (любая попытка изменить массив приведет к исключению). Но если все, что вам нужно, это прочитать данные, это отлично работает и не требует выделения места подкачки, я не думаю.
Другая возможность - открыть с помощью mode='update'
. Затем любые изменения в массиве можно синхронизировать непосредственно с файлом, что нормально, если вы этого хотите, но, очевидно, не так много, если вы этого не сделаете.
Глядя на страницу руководства, похоже, что есть также флаг, по крайней мере в Linux, с именем MAP_NORESERVE
который не позволяет заранее выделять пространство для копирования при записи. Так что, если вам не _ нужно_ записывать какие-либо изменения во весь массив, это тоже может сработать. Но мы должны быть в состоянии поймать SIGSEGV, который возникает, если у вас заканчивается пространство подкачки.
Удалось воспроизвести это напрямую - действительно, оба предложенных мной обходных пути ( mode='denywrite'
и mode='update'
работают. Я все равно буду пытаться посмотреть, что я могу сделать с MAP_NORESERVE
, и в противном случае выявление этой ошибки и предоставление более точного сообщения об ошибке.
Раздражение: numpy.memmap
не позволяет настраивать флаги, которые передаются вызову mmap
. Смотря на это, это не более чем легкий подкласс ndarray
который выполняет работу по созданию mmap с правильными флагами, а затем вызывает ndarray.__new__
с mmap в качестве его буфера. Он также добавляет метод flush
.
Должно быть достаточно легко просто отказаться от использования numpy.memmap
и обрабатывать mmap самостоятельно. Но это все еще больше, чем я хочу сейчас делать. Поэтому вместо этого я решу эту проблему, обнаружив ошибку и предложив один из существующих обходных путей.
Обратите внимание, что с # 7597 мы больше не используем np.memmap
, поэтому будет проще использовать другие флаги, если это полезно.
Теперь это можно закрыть, так как обходной путь был объединен в https://github.com/astropy/astropy/pull/7926. MAP_NORESERVE
недоступен в Python, поэтому, к сожалению, это не решение.