2013-09-23 6 views
5

Я пытаюсь найти происхождение неприятной утечки памяти в программе Python/NumPy с использованием расширений C/Cython и multiprocessing.Отладка утечки памяти Python/NumPy

Каждый подпроцесс обрабатывает список изображений, и каждый из них отправляет выходной массив (который обычно составляет около 200-300 МБ) через Queue в основной процесс. Достаточно стандартная карта/сокращение настроек.

Как вы можете себе представить, утечка памяти может принимать большие размеры с массивами, которые являются большими, и с несколькими процессами с радостью переходят на 20 ГБ оперативной памяти, когда им понадобится только 5-6 ГБ ... раздражает.

  • Я попытался запустить отладки сборки Python через Valgrind и четверной проверил мои расширения утечек памяти, но ничего не нашли.

  • Я проверил свой код на Python для зависания ссылок на мои массивы, а также использовал NumPy allocation tracker, чтобы проверить, действительно ли мои массивы были выпущены. Они были.

Последнее, что я сделал, это прикрепление GDB на один из моих процессов (это плохой мальчик сейчас работает на 27GB оперативной памяти и подсчета голосов) и демпинг большую часть кучи на диск. К моему большому удивлению, сброшенный файл был полон нулей! Около 7G стоит нулей.

Является ли это стандартным положением распределения памяти в Python/NumPy? Я пропустил что-то очевидное, что объясняло бы, что столько памяти использовалось для ничего? Как я могу правильно управлять памятью?


EDIT: Для записи, я бегу NumPy 1.7.1 и Python 2.7.3.

EDIT 2: Я контролировала процесс с strace, и кажется, что она продолжает увеличивать точку останова каждого процесса (с использованием brk() системного вызова).

Действительно ли CPython правильно освобождает память? Что относительно расширений C, массивов NumPy? Кто решает, когда позвонить brk(), это сам Python или это базовая библиотека (libc, ...)?

Ниже приведен пример журнала strace с комментариями, начиная с одной итерации (то есть с одного набора входных изображений). Обратите внимание, что точка останова продолжает расти, но я убедился (с objgraph), что никаких значимых массивов NumPy не содержится внутри интерпретатора Python.

# Reading .inf files with metadata 
# Pretty small, no brk() 
open("1_tif_all/AIR00642_1.inf", O_RDONLY) = 6 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000 
munmap(0x7f9387fff000, 4096)   = 0 
open("1_tif_all/AIR00642_2.inf", O_RDONLY) = 6 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000 
munmap(0x7f9387fff000, 4096)   = 0 
open("1_tif_all/AIR00642_3.inf", O_RDONLY) = 6 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000 
munmap(0x7f9387fff000, 4096)   = 0 
open("1_tif_all/AIR00642_4.inf", O_RDONLY) = 6 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000 
munmap(0x7f9387fff000, 4096)   = 0 

# This is where I'm starting the heavy processing 
write(2, "[INFO/MapProcess-1] Shot 642: Da"..., 68) = 68 
write(2, "[INFO/MapProcess-1] Shot 642: Vi"..., 103) = 103 
write(2, "[INFO/MapProcess-1] Shot 642: Re"..., 66) = 66 

# I'm opening a .tif image (752 x 480, 8-bit, 1 channel) 
open("1_tif_all/AIR00642_3.tif", O_RDONLY) = 6 
read(6, "II*\0JC\4\0", 8)    = 8 
mmap(NULL, 279600, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fbb000 
munmap(0x7f9387fbb000, 279600)   = 0 
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 53) = 53 

# Another .tif 
open("1_tif_all/AIR00642_4.tif", O_RDONLY) = 6 
read(6, "II*\0\266\374\3\0", 8)   = 8 
mmap(NULL, 261532, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fc0000 
munmap(0x7f9387fc0000, 261532)   = 0 
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 51) = 51 
brk(0x1aea97000)      = 0x1aea97000 

# Another .tif 
open("1_tif_all/AIR00642_1.tif", O_RDONLY) = 6 
read(6, "II*\0\220\253\4\0", 8)   = 8 
mmap(NULL, 306294, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fb5000 
munmap(0x7f9387fb5000, 306294)   = 0 
brk(0x1af309000)      = 0x1af309000 
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 53) = 53 
brk(0x1b03da000)      = 0x1b03da000 

# Another .tif 
open("1_tif_all/AIR00642_2.tif", O_RDONLY) = 6 
mmap(NULL, 345726, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fab000 
munmap(0x7f9387fab000, 345726)   = 0 
brk(0x1b0c42000)      = 0x1b0c42000 
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 51) = 51 

# I'm done reading my images 
write(2, "[INFO/MapProcess-1] Shot 642: Fi"..., 72) = 72 

# Allocating some more arrays for additional variables 
# Increases by about 8M at a time 
brk(0x1b1453000)      = 0x1b1453000 
brk(0x1b1c63000)      = 0x1b1c63000 
brk(0x1b2473000)      = 0x1b2473000 
brk(0x1b2c84000)      = 0x1b2c84000 
brk(0x1b3494000)      = 0x1b3494000 
brk(0x1b3ca5000)      = 0x1b3ca5000 

# What are these mmap calls doing here? 
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9377df1000 
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9367be2000 
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93579d3000 
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93477c4000 
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93375b5000 
munmap(0x7f93579d3000, 270594048)  = 0 
munmap(0x7f93477c4000, 270594048)  = 0 
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93579d3000 
munmap(0x7f93375b5000, 270594048)  = 0 
mmap(NULL, 50737152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9354970000 
munmap(0x7f9354970000, 50737152)  = 0 
brk(0x1b4cc6000)      = 0x1b4cc6000 
brk(0x1b5ce7000)      = 0x1b5ce7000 

EDIT 3:Is freeing handled differently for small/large numpy arrays? может быть уместным. Я все больше убеждаюсь, что я просто выделяю слишком много массивов, которые не попадают в систему, потому что это действительно стандартное поведение. Постарайтесь заранее распределить мои массивы и использовать их по мере необходимости.

+0

Что вы используете для чтения файлов изображений? У меня были проблемы с утечкой памяти с объектами PIL 'Image' в прошлом –

+0

Я использую привязки PyLibTiff. И я решил это, посмотри на мой ответ! –

ответ

1

Doh. I действительно должен был проверить эти расширения C в пятый раз.

Я забыл уменьшить счетчик ссылок в одном из временных массивов NumPy, которые я выделил из C. Массив не оставил код C, поэтому я не видел, что мне нужно его освободить.

Я до сих пор не знаю, почему он не появился в objgraph.

Смежные вопросы