Почему такое использование WriteBatch py-leveldb вызывает утечку памяти?

Поэтому я пишу скрипт Python для индексации блокчейна Биткойн по адресам, используя базу данных leveldb (py -leveldb), и он потребляет все больше и больше памяти, пока не выйдет из строя. Я воспроизвел поведение в приведенном ниже примере кода. Когда я запускаю код, он продолжает использовать все больше и больше памяти, пока не исчерпает доступную оперативную память в моей системе, и процесс либо будет убит, либо выдаст «std::bad_alloc».

Я делаю что-то неправильно? Я продолжаю писать в пакетный объект и время от времени фиксирую его, но использование памяти продолжает увеличиваться, даже несмотря на то, что я фиксирую данные в объекте WriteBatch. Я даже удаляю объект WriteBatch после его фиксации, поэтому, насколько я понимаю, это не может быть причиной утечки памяти.

Мой код неправильно использует WriteBatch или есть утечка памяти в py-leveldb?

Для запуска кода требуется py-leveldb. Получите его отсюда: https://pypi.python.org/pypi/leveldb

ВНИМАНИЕ: ЗАПУСК ЭТОГО КОДА ЗАГРУЗИТ ВАШУ ПАМЯТЬ, ЕСЛИ ОН ПРОДОЛЖАЕТСЯ ДОСТАТОЧНО ДОЛГО. НЕ ЗАПУСКАЙТЕ НА КРИТИЧЕСКИХ СИСТЕМАХ. Кроме того, он будет записывать данные в папку в той же папке, в которой запускается скрипт, в моей системе эта папка содержит около 1,5 ГБ файлов базы данных до исчерпания памяти. (в конечном итоге он потребляет более 3 ГБ ОЗУ).

Вот код:

import leveldb, random, string

RANDOM_DB_NAME = "db-DetmREnTrKjd"
KEYLEN = 10
VALLEN = 30
num_keys = 1000
iterations = 100000000
commit_every = 1000000

leveldb.DestroyDB(RANDOM_DB_NAME)
db = leveldb.LevelDB(RANDOM_DB_NAME)

batch = leveldb.WriteBatch()

#generate a random list of keys to be used
key_list = [''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(KEYLEN)) for i in range(0,num_keys)]

for k in xrange(iterations):
    #select a random key from the key list
    key_index = random.randrange(0,1000)
    key = key_list[key_index]

    try:
        prev_val = db.Get(key)
    except KeyError:
        prev_val = ""

    random_val = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(VALLEN))
    #write the current random value plus any value that might already be there
    batch.Put(key, prev_val + random_val)

    if k % commit_every == 0:
        print "Comitting batch %d/%d..." % (k/commit_every, iterations/commit_every)
        db.Write(batch, sync=True)
        del batch
        batch = leveldb.WriteBatch()

db.Write(batch, sync=True)

person runeks    schedule 27.08.2013    source источник


Ответы (2)


Вместо этого вам стоит попробовать Plyvel. См. https://plyvel.readthedocs.org/. У него более чистый код, больше функций, больше скорости и гораздо больше тестов. Я использовал его для массовой записи в довольно большие базы данных (20+ ГБ) без каких-либо проблем.

(Полное раскрытие: я автор.)

person wouter bolsterlee    schedule 27.11.2013

Я использую http://code.google.com/p/leveldb-py/.

У меня недостаточно информации для участия в тестировании драйвера leveldb для Python, но мне нравится простота leveldb-py. Это один файл Python, использующий ctypes. Я использовал его для хранения документов примерно в 3 миллионах ключей, хранящих около 10 ГБ, и никогда не замечал проблем с памятью.

К вашей реальной проблеме: вы можете попробовать работать с размером партии.

Ваш код, использующий leveldb-py и выполняющий put для каждого ключа, отлично работал в моей системе, используя менее 20 МБ памяти.

Я беру отсюда (http://ayende.com/blog/161412/reviewing-leveldb-part-iii-writebatch-isnt-what-you-think-it-is), что под капюшон в leveldb.

person bauman.space    schedule 13.12.2013