весёлые разборки с питоном и glibc
Jun. 14th, 2012 08:28 amОкружение: Linux/x86-64/glibc
I. Питон.
Берём небольшую тестовую программку:
Если её запустить под 2.7 в описанном виде, получаем:
Сделав одно небольшое изменение - A наследуется от object (и становится new style class) - получаем:
Формально new style легче буквально на десяток байт, но меняется что-то другое. Теперь запустим вообще под python3:
Раньше мы меряли потребление памяти тяжёлым процессом по пиковым нагрузкам, но это, как видно, уже неадекватный результат.
Кстати, окончательное освобождение из-под объектов происходит именно при gc.collect(). До этого чистится чуть-чуть (насколько я понял, собственно список, но не объекты).
Но!!! Как только мы создаём не пустой объект, а с реальным содержимым, память перестаёт освобождаться по удалению объектов:(
II. Уже Си (чтобы избавиться от возможных эффектов Питона). Тестовая программа порождает 50 тредов, после каждых 10 рассказывая объём процесса, каждый тред делает malloc(1) и уходит в вечный цикл сна. Запускаем... ой...
64MB на тред не включая 8MB стека до какого-то порога - это пять. косяков.
Теория см. здесь. И точно:
А всего-то хотелось соотнести объём процесса с нагрузкой и придумать, как определять, что с ним что-то не так (например. забытый, но не удалённый и не отцеплённый, мусор в памяти). Но, видимо, просто не решится.
I. Питон.
Берём небольшую тестовую программку:
import os, gc
def ps():
os.system("ps -p %s -o vsz,rss | tail -n +2" % (os.getpid(),))
class A:
pass
ps()
a = [A() for x in range(0,3000000)]
ps()
del a; gc.collect()
ps()
Если её запустить под 2.7 в описанном виде, получаем:
20996 4456 1182596 1161900 936816 920336
Сделав одно небольшое изменение - A наследуется от object (и становится new style class) - получаем:
20996 4452 314112 293528 93032 76660
Формально new style легче буквально на десяток байт, но меняется что-то другое. Теперь запустим вообще под python3:
28872 6956 249692 224164 28872 7196
Раньше мы меряли потребление памяти тяжёлым процессом по пиковым нагрузкам, но это, как видно, уже неадекватный результат.
Кстати, окончательное освобождение из-под объектов происходит именно при gc.collect(). До этого чистится чуть-чуть (насколько я понял, собственно список, но не объекты).
Но!!! Как только мы создаём не пустой объект, а с реальным содержимым, память перестаёт освобождаться по удалению объектов:(
II. Уже Си (чтобы избавиться от возможных эффектов Питона). Тестовая программа порождает 50 тредов, после каждых 10 рассказывая объём процесса, каждый тред делает malloc(1) и уходит в вечный цикл сна. Запускаем... ой...
6120 372 743572 2640 1480892 6736 2218212 8972 2365708 13068 2447668 13068
64MB на тред не включая 8MB стека до какого-то порога - это пять. косяков.
Теория см. здесь. И точно:
$ env MALLOC_ARENA_MAX=1 ./t1 6120 372 612500 4688 694460 4688 776420 4868 858380 4868 940340 5060
А всего-то хотелось соотнести объём процесса с нагрузкой и придумать, как определять, что с ним что-то не так (например. забытый, но не удалённый и не отцеплённый, мусор в памяти). Но, видимо, просто не решится.
no subject
Date: 2012-06-14 02:00 pm (UTC)Можно короче:
sum(int(line.split()[1]) for line in open('/proc/%s/smaps' % (xpid,)) if '_Dirty:' in line)Или на шелле:
grep _Dirty: /proc/$1/smaps | numsum -c | cut -d' ' -f2