Pertanyaan Bagaimana saya menemukan apa yang menggunakan memori dalam proses Python dalam sistem produksi?


Sistem produksi saya kadang-kadang menunjukkan kebocoran memori saya belum dapat mereproduksi dalam lingkungan pengembangan. Saya telah menggunakan Profiler memori Python (Khususnya, Heapy) dengan beberapa keberhasilan dalam lingkungan pengembangan, tetapi itu tidak dapat membantu saya dengan hal-hal yang tidak dapat saya perbanyak, dan saya enggan mendokumentasikan sistem produksi kami dengan Heapy karena butuh waktu beberapa saat untuk melakukan hal itu dan antarmuka remote berulir tidak berfungsi dengan baik di server kami.

Apa yang saya pikir saya inginkan adalah cara untuk membuang snapshot dari proses produksi Python (atau setidaknya gc.get_objects), dan kemudian menganalisanya secara offline untuk melihat di mana ia menggunakan memori. Bagaimana cara mendapatkan dump inti dari proses python seperti ini?  Setelah saya memilikinya, bagaimana saya melakukan sesuatu yang bermanfaat dengannya?


34
2017-09-26 19:13


asal


Jawaban:


Menggunakan Python gc antarmuka pengumpul sampah dan sys.getsizeof() itu mungkin untuk membuang semua benda python dan ukurannya. Inilah kode yang saya gunakan dalam produksi untuk memecahkan masalah kebocoran memori:

rss = psutil.Process(os.getpid()).get_memory_info().rss
# Dump variables if using more than 100MB of memory
if rss > 100 * 1024 * 1024:
    memory_dump()
    os.abort()

def memory_dump():
    dump = open("memory.pickle", 'w')
    for obj in gc.get_objects():
        i = id(obj)
        size = sys.getsizeof(obj, 0)
        #    referrers = [id(o) for o in gc.get_referrers(obj) if hasattr(o, '__class__')]
        referents = [id(o) for o in gc.get_referents(obj) if hasattr(o, '__class__')]
        if hasattr(obj, '__class__'):
            cls = str(obj.__class__)
            cPickle.dump({'id': i, 'class': cls, 'size': size, 'referents': referents}, dump)

Perhatikan bahwa saya hanya menyimpan data dari objek yang memiliki __class__ atribut karena itu adalah satu-satunya objek yang saya pedulikan. Seharusnya mungkin untuk menyimpan daftar lengkap objek, tetapi Anda harus berhati-hati memilih atribut lain. Juga, saya menemukan bahwa mendapatkan perujuk untuk setiap objek sangat lambat jadi saya memilih untuk menyimpan hanya referensi. Bagaimanapun, setelah kecelakaan, data acar yang dihasilkan dapat dibaca kembali seperti ini:

dump = open("memory.pickle")
while dump:
    obj = cPickle.load(dump)

Ditambahkan 2017-11-15

Versi Python 3.6 ada di sini:

import gc
import sys
import _pickle as cPickle

def memory_dump():
    with open("memory.pickle", 'wb') as dump:
        for obj in gc.get_objects():
            i = id(obj)
            size = sys.getsizeof(obj, 0)
            #    referrers = [id(o) for o in gc.get_referrers(obj) if hasattr(o, '__class__')]
            referents = [id(o) for o in gc.get_referents(obj) if hasattr(o, '__class__')]
            if hasattr(obj, '__class__'):
                cls = str(obj.__class__)
                cPickle.dump({'id': i, 'class': cls, 'size': size, 'referents': referents}, dump)

27
2018-03-05 13:56



Bisakah Anda merekam lalu lintas (melalui log) di situs produksi Anda, kemudian memainkannya kembali di server pengembangan Anda yang diinstrumentasi dengan debugger memori python? (Saya merekomendasikan dozer: http://pypi.python.org/pypi/Dozer)


5
2017-09-26 23:41



Saya tidak tahu bagaimana cara membuang seluruh status penerjemah python dan memulihkannya. Ini akan berguna, saya akan terus mengawasi jawaban ini jika ada orang lain yang memiliki ide.

Jika Anda memiliki ide di mana memori bocor, Anda dapat menambahkan memeriksa jumlah objek Anda. Sebagai contoh:

x = SomeObject()
... later ...
oldRefCount = sys.getrefcount( x )
suspiciousFunction( x )
if (oldRefCount != sys.getrefcount(x)):
    print "Possible memory leak..."

Anda juga dapat memeriksa jumlah referensi yang lebih tinggi dari beberapa nomor yang masuk akal untuk aplikasi Anda. Untuk mengambil lebih jauh, Anda dapat memodifikasi interpreter python untuk melakukan pemeriksaan semacam ini dengan mengganti Py_INCREF dan Py_DECREF macro dengan milik Anda sendiri. Ini mungkin sedikit berbahaya dalam aplikasi produksi.

Ini adalah esai dengan lebih banyak info tentang hal-hal semacam ini. Ini lebih diarahkan untuk penulis plugin tetapi sebagian besar berlaku.

Hitung Referensi Debugging


2
2017-09-26 21:37



Jadikan program Anda membuang inti, kemudian mengkloning turunan dari program pada penggunaan kotak yang serupa gdb. Ada makro khusus untuk membantu dengan program python debugging dalam gdb, tetapi jika Anda bisa mendapatkan program Anda secara bersamaan sajikan shell jarak jauh, Anda bisa melanjutkan eksekusi program, dan menanyakannya dengan python.

Saya tidak pernah melakukan ini, jadi saya tidak yakin 100% akan berhasil, tetapi mungkin petunjuknya akan sangat membantu.


2
2017-09-27 00:11



Meliae terlihat menjanjikan:

Proyek ini mirip dengan heapy (dalam proyek 'guppy'), dalam usahanya untuk memahami bagaimana memori telah dialokasikan.

Saat ini, perbedaan utamanya adalah bahwa membagi tugas komputasi statistik ringkasan, dll konsumsi memori dari pemindaian yang sebenarnya dari konsumsi memori. Ini melakukan ini, karena saya sering ingin mencari tahu apa yang sedang terjadi dalam proses saya, sementara proses saya memakan banyak memori (1GB, dll). Ini juga memungkinkan menyederhanakan pemindai secara dramatis, karena saya tidak mengalokasikan objek python ketika mencoba untuk menganalisis konsumsi memori objek python.


2
2018-01-31 00:16



Itu gc modul memiliki beberapa fungsi yang mungkin berguna, seperti daftar semua objek yang ditemukan pengumpul sampah tidak dapat dijangkau tetapi tidak bisa gratis, atau daftar semua objek yang dilacak.

Jika Anda memiliki kecurigaan yang mungkin bocor objek, weakref Modul bisa berguna untuk mengetahui apakah / ketika objek dikumpulkan.


1
2017-09-26 21:45