Saya menulis sebuah program Python yang bertindak pada file input besar untuk membuat beberapa juta objek yang mewakili segitiga. Algoritme adalah:
- baca file input
- memproses file dan membuat daftar segitiga, diwakili oleh simpulnya
- mengeluarkan simpul dalam format OFF: daftar simpul diikuti oleh daftar segitiga. Segitiga diwakili oleh indeks ke dalam daftar simpul
Persyaratan MATI yang saya cetak daftar lengkap simpul sebelum saya mencetak segitiga berarti bahwa saya harus memegang daftar segitiga dalam memori sebelum saya menulis output ke file. Sementara itu saya mendapatkan kesalahan memori karena ukuran daftar.
Apa cara terbaik untuk memberi tahu Python bahwa saya tidak lagi memerlukan beberapa data, dan itu bisa dibebaskan?
python
memory
memory-management
Nathan Fellman
sumber
sumber
Jawaban:
Menurut Dokumentasi Resmi Python , Anda dapat memaksa Pengumpul Sampah untuk melepaskan memori yang tidak direferensikan
gc.collect()
. Contoh:sumber
gc.collect()
diri sendiri di akhir perulangan dapat membantu menghindari memecah-mecah memori, yang pada gilirannya membantu menjaga kinerja tetap tinggi. Saya telah melihat ini membuat perbedaan yang signifikan (~ 20% runtime IIRC)gc.collect()
setelah memuat bingkai data panda dari hdf5 (baris 500k) mengurangi penggunaan memori dari 1,7GB menjadi 500MBdel my_array
diikuti olehgc.collect()
setelah memproses array adalah satu-satunya cara memori sebenarnya dilepaskan dan proses saya bertahan untuk memuat array berikutnya.Sayangnya (tergantung pada versi Anda dan rilis Python) beberapa jenis objek menggunakan "daftar gratis" yang merupakan optimasi lokal yang rapi tetapi dapat menyebabkan fragmentasi memori, khususnya dengan membuat lebih banyak dan lebih banyak memori "disisihkan" untuk hanya objek dari jenis tertentu dan dengan demikian tidak tersedia untuk "dana umum".
Satu-satunya cara yang benar-benar dapat diandalkan untuk memastikan bahwa penggunaan memori yang besar namun sementara TIDAK mengembalikan semua sumber daya ke sistem ketika selesai, adalah membuat penggunaan itu terjadi dalam subproses, yang kemudian dihentikan oleh pekerjaan yang haus memori. Dalam kondisi seperti itu, sistem operasi AKAN melakukan tugasnya, dan dengan senang hati mendaur ulang semua sumber daya yang mungkin telah diproses oleh subproses. Untungnya,
multiprocessing
modul ini membuat operasi semacam ini (yang dulunya agak menyebalkan) tidak terlalu buruk di versi modern Python.Dalam kasus penggunaan Anda, tampaknya cara terbaik bagi subproses untuk mengakumulasikan beberapa hasil dan memastikan hasil tersebut tersedia untuk proses utama adalah dengan menggunakan file semi-temporer (maksudnya semi-temporer, BUKAN jenis file yang secara otomatis hilang ketika ditutup, hanya file biasa yang Anda hapus secara eksplisit ketika Anda selesai melakukannya).
sumber
multiprocessing.Manager
daripada file untuk menerapkan status bersama.The
del
Pernyataan mungkin digunakan, tetapi IIRC itu tidak dijamin untuk membebaskan memori . The docs di sini ... dan mengapa tidak dirilis di sini .Saya telah mendengar orang-orang di sistem Linux dan Unix-type forking proses python untuk melakukan beberapa pekerjaan, mendapatkan hasil dan kemudian membunuhnya.
Artikel ini memiliki catatan tentang pengumpul sampah Python, tapi saya pikir kurangnya kontrol memori adalah kelemahan dari memori yang dikelola
sumber
Python dikumpulkan dari sampah, jadi jika Anda mengurangi ukuran daftar Anda, itu akan mendapatkan kembali memori. Anda juga dapat menggunakan pernyataan "del" untuk menyingkirkan variabel sepenuhnya:
sumber
Anda tidak dapat secara eksplisit membebaskan memori. Yang perlu Anda lakukan adalah memastikan Anda tidak menyimpan referensi ke objek. Mereka kemudian akan menjadi sampah yang dikumpulkan, membebaskan memori.
Dalam kasus Anda, ketika Anda membutuhkan daftar besar, Anda biasanya perlu mengatur ulang kode, biasanya menggunakan generator / iterator. Dengan begitu Anda tidak perlu memiliki daftar besar dalam memori sama sekali.
http://www.prasannatech.net/2009/07/introduction-python-generators.html
sumber
(
del
bisa jadi teman Anda, karena menandai objek sebagai dihapus ketika tidak ada referensi lain untuk mereka. Sekarang, sering kali juru bahasa CPython menyimpan memori ini untuk digunakan nanti, sehingga sistem operasi Anda mungkin tidak melihat memori "bebas".)Mungkin Anda tidak akan mengalami masalah memori di tempat pertama dengan menggunakan struktur yang lebih kompak untuk data Anda. Dengan demikian, daftar angka jauh lebih sedikit memori-efisien daripada format yang digunakan oleh
array
modul standar atau modul pihak ketiganumpy
. Anda akan menghemat memori dengan meletakkan simpul Anda dalam array NumPy 3xN dan segitiga Anda dalam array N-elemen.sumber
del
tidak melakukan apa pun yang hanya menetapkan ulang nilai yang berbeda untuk semua nama yang merujuk objek tidak.del
membebaskan memori dari sudut pandang Python, tetapi umumnya tidak dari sudut pandang C runtime library atau OS. Referensi: stackoverflow.com/a/32167625/4297 , effbot.org/pyfaq/… .del
sama efektifnya dengan keluar-dari-lingkup, penugasan kembali, dllSaya memiliki masalah yang sama dalam membaca grafik dari file. Pemrosesan termasuk perhitungan matriks float 200 000x200 000 (satu baris pada suatu waktu) yang tidak sesuai dengan memori. Mencoba membebaskan memori di antara komputasi menggunakan
gc.collect()
memperbaiki aspek yang terkait dengan memori dari masalah tetapi mengakibatkan masalah kinerja: Saya tidak tahu mengapa tetapi meskipun jumlah memori yang digunakan tetap konstan, setiap panggilan barugc.collect()
membutuhkan waktu lebih lama daripada yang sebelumnya. Jadi, cukup cepat pengumpulan sampah menghabiskan sebagian besar waktu perhitungan.Untuk memperbaiki masalah memori dan kinerja saya beralih ke penggunaan trik multithreading yang saya baca sekali di suatu tempat (maaf, saya tidak dapat menemukan posting terkait lagi). Sebelum saya membaca setiap baris file dalam satu
for
lingkaran besar , memprosesnya, dan menjalankannyagc.collect()
sesekali untuk membebaskan ruang memori. Sekarang saya memanggil fungsi yang membaca dan memproses sepotong file di utas baru. Setelah utas berakhir, memori secara otomatis dibebaskan tanpa masalah kinerja yang aneh.Praktisnya bekerja seperti ini:
sumber
Yang lain telah memposting beberapa cara yang mungkin dapat "membujuk" juru bahasa Python agar membebaskan memori (atau menghindari masalah memori). Kemungkinannya adalah Anda harus mencoba ide mereka terlebih dahulu. Namun, saya merasa penting untuk memberi Anda jawaban langsung untuk pertanyaan Anda.
Sebenarnya tidak ada cara untuk secara langsung memberitahu Python untuk membebaskan memori. Faktanya adalah bahwa jika Anda ingin tingkat kontrol yang rendah, Anda harus menulis ekstensi dalam C atau C ++.
Yang mengatakan, ada beberapa alat untuk membantu ini:
sumber
Jika Anda tidak peduli tentang penggunaan kembali verteks, Anda bisa memiliki dua file output - satu untuk simpul dan satu untuk segitiga. Kemudian tambahkan file segitiga ke file titik setelah Anda selesai.
sumber