Попробуйте -XX:MaxPermSize=256m
и если это сохраняется, попробуйте -XX:MaxPermSize=512m
Вы пробовали использовать __ slots __
?
Из документация :
По умолчанию экземпляры классов как старого, так и нового стиля имеют словарь для хранения атрибутов. Это тратит пространство для объектов, имеющих очень мало переменных экземпляра. При создании большого количества экземпляров может потребоваться много места.
Значение по умолчанию можно изменить, указав
__ slots __
в определении класса нового стиля. Объявление__ slots __
принимает последовательность переменных экземпляра и резервирует достаточно места в каждом экземпляре для хранения значения для каждой переменной. Место экономится, потому что__ dict __
не создается для каждого экземпляра.
Так это экономит время, а также память?
Сравнение трех подходов на моем компьютере:
test_slots.py:
class Obj(object):
__slots__ = ('i', 'l')
def __init__(self, i):
self.i = i
self.l = []
all = {}
for i in range(1000000):
all[i] = Obj(i)
test_obj.py:
class Obj(object):
def __init__(self, i):
self.i = i
self.l = []
all = {}
for i in range(1000000):
all[i] = Obj(i)
test_dict.py:
all = {}
for i in range(1000000):
o = {}
o['i'] = i
o['l'] = []
all[i] = o
test_ namedtuple.py (поддерживается в 2.6):
import collections
Obj = collections.namedtuple('Obj', 'i l')
all = {}
for i in range(1000000):
all[i] = Obj(i, [])
Выполнить тест (с использованием CPython 2.5):
$ lshw | grep product | head -n 1
product: Intel(R) Pentium(R) M processor 1.60GHz
$ python --version
Python 2.5
$ time python test_obj.py && time python test_dict.py && time python test_slots.py
real 0m27.398s (using 'normal' object)
real 0m16.747s (using __dict__)
real 0m11.777s (using __slots__)
Использование CPython 2.6.2, включая тест именованного кортежа :
$ python --version
Python 2.6.2
$ time python test_obj.py && time python test_dict.py && time python test_slots.py && time python test_namedtuple.py
real 0m27.197s (using 'normal' object)
real 0m17.657s (using __dict__)
real 0m12.249s (using __slots__)
real 0m12.262s (using namedtuple)
Так что да (не удивительно), использование __ slots __
- это оптимизация производительности.
Доступ к атрибутам в объекте использует скрытый доступ к словарю, поэтому, используя доступ к атрибутам, вы добавляете дополнительные накладные расходы. Кроме того, в случае с объектами вы несете дополнительные накладные расходы, например, из-за выделения дополнительной памяти и выполнения кода (например, метода __ init __
).
В вашем коде, если o
равно экземпляр Obj
, o.attr
эквивалентен o .__ dict __ ['attr']
с небольшими дополнительными накладными расходами.
Рассматривали ли вы использование namedtuple ? ( ссылка для python 2.4 / 2.5 )
Это новый стандартный способ представления структурированных данных, который дает вам производительность кортежа и удобство класса.
Это только обратная сторона по сравнению со словарями в том, что (как и кортежи) он не дает вам возможности изменять атрибуты после создания.
from datetime import datetime
ITER_COUNT = 1000 * 1000
def timeit(method):
def timed(*args, **kw):
s = datetime.now()
result = method(*args, **kw)
e = datetime.now()
print method.__name__, '(%r, %r)' % (args, kw), e - s
return result
return timed
class Obj(object):
def __init__(self, i):
self.i = i
self.l = []
class SlotObj(object):
__slots__ = ('i', 'l')
def __init__(self, i):
self.i = i
self.l = []
@timeit
def profile_dict_of_dict():
return dict((i, {'i': i, 'l': []}) for i in xrange(ITER_COUNT))
@timeit
def profile_list_of_dict():
return [{'i': i, 'l': []} for i in xrange(ITER_COUNT)]
@timeit
def profile_dict_of_obj():
return dict((i, Obj(i)) for i in xrange(ITER_COUNT))
@timeit
def profile_list_of_obj():
return [Obj(i) for i in xrange(ITER_COUNT)]
@timeit
def profile_dict_of_slotobj():
return dict((i, SlotObj(i)) for i in xrange(ITER_COUNT))
@timeit
def profile_list_of_slotobj():
return [SlotObj(i) for i in xrange(ITER_COUNT)]
if __name__ == '__main__':
profile_dict_of_dict()
profile_list_of_dict()
profile_dict_of_obj()
profile_list_of_obj()
profile_dict_of_slotobj()
profile_list_of_slotobj()
Результаты:
hbrown@hbrown-lpt:~$ python ~/Dropbox/src/StackOverflow/1336791.py
profile_dict_of_dict ((), {}) 0:00:08.228094
profile_list_of_dict ((), {}) 0:00:06.040870
profile_dict_of_obj ((), {}) 0:00:11.481681
profile_list_of_obj ((), {}) 0:00:10.893125
profile_dict_of_slotobj ((), {}) 0:00:06.381897
profile_list_of_slotobj ((), {}) 0:00:05.860749
Нет вопросов.
У вас есть данные без других атрибутов (без методов, ничего). Следовательно, у вас есть контейнер данных (в данном случае словарь).
Я обычно предпочитаю думать в терминах моделирования данных . Если возникает серьезная проблема с производительностью, я могу отказаться от чего-то в абстракции, но только по очень веским причинам.
Программирование - это управление сложностью, и поддержание правильной абстракции очень часто является одним из наиболее полезных способов достижения такого результата.
О причинах объект работает медленнее, Я считаю, что ваши измерения неверны.
Вы выполняете слишком мало присваиваний внутри цикла for, и поэтому вы видите разное время, необходимое для создания экземпляра dict (внутреннего объекта) и «настраиваемого» объекта. Хотя с точки зрения языка они одинаковы, но имеют совершенно разную реализацию.
После этого время назначения должно быть почти одинаковым для обоих, так как конечные члены поддерживаются в словаре.