У меня есть сетевой процесс, который связывается по TCP, собирая данные, десериализуя их и, наконец, сохраняя части в хранилище ключей / значений LevelDB (через Plyvel ).
Медленно со временем он будет использовать всю доступную память до такой степени, что вся моя система блокируется (Ubuntu 18.04). Я пытаюсь диагностировать причину, но у меня заканчиваются идеи, как продолжить расследование.
Основные подозреваемые, которые я имею в виду, - это потоки данных, с которыми мы работаем для десериализации объектов. Общее, что здесь сделано: получение данных от asyncio.StreamReader и вызов deserialize_from_bytes
(см. Далее)
@classmethod
def deserialize_from_bytes(cls, data_stream: Union[bytes, bytearray]):
""" Deserialize object from a byte array. """
br = BinaryReader(stream=data_stream)
inv_payload = cls()
try:
inv_payload.deserialize(br)
except ValueError:
return None
finally:
br.cleanup()
return inv_payload
где BinaryReader
инициализируется так
def __init__(self, stream: Union[io.BytesIO, bytes, bytearray]) -> None:
super(BinaryReader, self).__init__()
if isinstance(stream, (bytearray, bytes)):
self._stream = io.BytesIO(stream)
else:
self._stream = stream
и cleanup()
- это удобная оболочка для self._stream.close()
Что я пробовал
Я начал с демонстрации фрагмента top 10 из tracemalloc
. В момент времени, когда /proc/$mypid/status
показывает использование памяти в 2 ГБ (на VmSize
), наиболее потребляющий элемент из tracemalloc
сообщает всего 38 МБ, за которым следуют второе и третье - 3 МБ и 360 КБ.
Это уже поднимает вопрос; где остальные ~ 1,995 ГБ?
Не помогло вышеприведенным выводом, который я пробовал objgraph . Я врываюсь в процесс с pdb
и использую
import objgraph
objgraph.show_most_common_types(limit=20)
чтобы получить
function 16451
tuple 11456
dict 10371
weakref 3058
list 2893
cell 2446
Traceback 2277
Statistic 2277
_Binding 2109
getset_descriptor 1814
type 1680
builtin_function_or_method 1469
wrapper_descriptor 1311
method_descriptor 1284
frozenset 992
property 983
module 810
ModuleSpec 808
SourceFileLoader 738
Attrs 593
В этом списке я не вижу объектов, относящихся к моей программе (которые могут указывать на то, что ссылки не были освобождены). Из других objgraph
примеров я обнаружил, что приведенные выше значения не кажутся необычными. Я проверил пару function
объектов и всегда находил что-то похожее на это (связанное с asyncio), которое не предполагает утечки памяти.
(Pdb) objgraph.at(0x10f309b70)
<function _run_coroutine.<locals>.step_next.<locals>.continue_ at 0x10f309b70>
Пожалуйста, поправьте меня здесь, если я что-то упустил. Опять же, без шага дальше
- Последняя попытка выяснить, могу ли я принудительно освободить любую память, я вручную запускаю gc.collect () . Повторный вызов этого дает значения между 25-500 для числа недоступных объектов. Это не вызывает у меня проблемы (не так ли?). Я также попытался запустить программу с
gc.set_debug(gc.DEBUG_LEAK)
, но это выдает настолько много информации, что я ничего не могу с этим поделать.
Какие-нибудь советы, что я могу попробовать здесь?