Ответ 1
для меня это тоже не имеет смысла, и я хотел выяснить, как и почему это происходит. (я думал, что это тоже сработает!) Я воспроизвел его на своей машине - хотя и с меньшим файлом.
я увидел две дискретные проблемы здесь
- Почему Python считывает файл в память (с ленивым чтением строки, это не должно быть?)
- почему Python не освобождает память для системы.
Я не знаю вообще о внутренних компонентах Python, поэтому я просто сделал много веб-поиска. Все это может быть совершенно не по себе. (Я едва развился больше, были на стороне бизнеса в течение последних нескольких лет)
Чтение ленивой строки...
Я огляделся и нашел этот пост -
http://www.peterbe.com/plog/blogitem-040312-1
это из гораздо более ранней версии python, но эта строка резонировала со мной:
readlines() читает во всем файле сразу и разбивает его по строке.
то я увидел это, также старое сообщение effbot:
http://effbot.org/zone/readline-performance.htm
ключевым выводом было следующее:
Например, если у вас достаточно памяти, вы можете разложить весь файл в память, используя метод readlines.
и это:
В Python 2.2 и более поздних версиях вы можете зацикливаться на самом объекте файла. Это очень похоже на readlines (N) под обложками, но выглядит намного лучше
просмотр документов pythons для xreadlines [http://docs.python.org/library/stdtypes.html?highlight=readline#file.xreadlines]:
Этот метод возвращает то же самое, что и iter (f) Устаревший с версии 2.3: вместо этого используется для строки в файле.
это заставило меня подумать, что, возможно, происходит какое-то проклятие.
поэтому, если мы посмотрим на строки read [http://docs.python.org/library/stdtypes.html?highlight=readline#file.readlines]...
Прочитайте до EOF, используя readline(), и верните список, содержащий прочитанные строки.
и это похоже на то, что происходит здесь.
readline, однако, выглядел так, как мы хотели [http://docs.python.org/library/stdtypes.html?highlight=readline#file.readline]
Прочитайте одну целую строку из файла
поэтому я попробовал переключить это на readline, и этот процесс никогда не рос выше 40 МБ (раньше он увеличивался до 200 МБ, размер файла журнала)
accounts = dict()
data= open(filename)
for line in data.readline():
info = line.split("LOG:")
if len(info) == 2 :
( a , b ) = info
try:
accounts[a].add(True)
except KeyError:
accounts[a] = set()
accounts[a].add(True)
Я предполагаю, что мы на самом деле не ленивы, читаем файл с конструкцией for x in data
, хотя все комментарии к документам и stackoverflow предполагают, что мы есть. readline()
потребляет значительно меньше памяти для меня, а realdlines
потребляет примерно тот же объем памяти, что и for line in data
освобождение памяти
с точки зрения освобождения памяти, я не очень хорошо знаком с внутренними компонентами Python, но я вспоминаю, когда работал с mod_perl... если бы я открыл файл размером 500 МБ, этот ребенок Apache вырос до такого размера, если бы я освободил память, он был бы свободен только внутри этого ребенка - собранная память мусора никогда не возвращалась в ОС до тех пор, пока процесс не завершится.
поэтому я подумал над этой идеей и нашел несколько ссылок, которые предполагают, что это может произойти:
http://effbot.org/pyfaq/why-doesnt-python-release-the-memory-when-i-delete-a-large-object.htm
Если вы создаете большой объект и снова удаляете его, Python, вероятно, выпустил эту память, но задействованные распределители памяти не обязательно возвращают память в операционную систему, поэтому может показаться, что процесс Python использует гораздо больше виртуальных памяти, чем она на самом деле использует.
который был вроде старым, и впоследствии я нашел кучу случайных (принятых) патчей в python, которые предложили изменить поведение и теперь вы можете вернуть память в os (по состоянию на 2005 год, когда большинство этих патчей были отправлены и, по-видимому, одобрен).
то я нашел это сообщение http://objectmix.com/python/17293-python-memory-handling.html - и отметьте комментарий # 4
"" - Патч # 1123430: Распределитель малых объектов Python теперь возвращает арену в систему
free()
, когда вся память внутри арены снова не используется. До Python 2.5 арены (256 Кбайт кусков памяти) никогда не были В некоторых приложениях снижается размер виртуальной памяти, особенно долгосрочные приложения, которые время от времени временно используют большое количество небольших объектов. Обратите внимание, что когда Python возвращает арену платформы Cfree()
нет никакой гарантии, что библиотека платформы C в свою очередь вернет эту память в операционную систему. Эффект патча заключается в том, чтобы прекратить делать это невозможным, а в тестах он, по-видимому, эффективен, по крайней мере, на системах Microsoft C и gcc. Спасибо Эван Джонсу за тяжелую работу и терпение.Итак, с 2.4 под linux (как вы тестировали) вы действительно не всегда получите используемая память назад, в отношении множества мелких объектов, являющихся собраны.
Разница, поэтому (я думаю), вы видите, что между f.read() и f.readlines() заключается в том, что первый читает во всем файле как один большой строковый объект (т.е. не маленький объект), а последний возвращает список строк, где каждая строка является объектом python.
если конструкция "для строки в данных:" по существу обертывается readlines
, а не readline
, может быть, это имеет какое-то отношение к ней? возможно, это не проблема наличия одного 3GB-объекта, но вместо этого есть миллионы 30 тыс. объектов.