的行爲我有一個Django應用程序表現出一些奇怪的垃圾收集行爲。特別是有一種觀點認爲,每次調用時都會顯着增加虛擬機的大小 - 達到某個限制,此時使用率會再次下降。問題是,直到達到這一點需要相當長的時間,事實上,運行我的應用程序的虛擬機沒有足夠的內存供所有FCGI進程佔用儘可能多的內存。的Python:垃圾收集
我花了最後兩天調查這和學習Python的垃圾收集,我想我明白現在發生的事情 - 大部分。當使用
gc.set_debug(gc.DEBUG_STATS)
那麼對於一個請求,我看到下面的輸出:
>>> c = django.test.Client()
>>> c.get('/the/view/')
gc: collecting generation 0...
gc: objects in each generation: 724 5748 147341
gc: done.
gc: collecting generation 0...
gc: objects in each generation: 731 6460 147341
gc: done.
[...more of the same...]
gc: collecting generation 1...
gc: objects in each generation: 718 8577 147341
gc: done.
gc: collecting generation 0...
gc: objects in each generation: 714 0 156614
gc: done.
[...more of the same...]
gc: collecting generation 0...
gc: objects in each generation: 715 5578 156612
gc: done.
所以基本上,一個巨大的物體的量分配,但最初轉移到第1,當根1在同一個請求期間被清除,它們被移到第二代。如果我之後做了一個手動gc.collect(2),它們將被刪除。而且,正如我所提到的那樣,當下一次自動生成第2代掃描時,它也會被刪除,如果我理解正確,在這種情況下,每10次請求就會有一次(此時應用程序需要大約150MB)。
好了,所以最初我認爲有可能是一些環狀引用其防止任何這些對象中的從處理請求內所收集一個請求的處理過程中繼續。然而,我花了數小時的時間試圖找到一個使用pympler.muppy和objgraph,在請求處理之後和之後進行調試,並且似乎沒有任何問題。相反,在請求期間創建的14.000個左右的對象似乎都是在某個請求全局對象的引用鏈內,即一旦請求消失,它們就可以被釋放。
這一直是我的企圖在解釋吧,反正。但是,如果這是真的,並確有沒有騎自行車的依賴關係,不應該對象的整個樹被釋放,一旦任何請求對象,使他們舉行消失,而不涉及垃圾收集,純粹憑藉引用計數的降至零?
使用這個配置,這裏是我的問題:
請問以上,甚至是有意義的,還是我不得不尋找其他地方的問題?這是一個不幸的事故,重要的數據在這個特定的用例中保存了很長時間嗎?
有什麼我可以做,以避免這個問題。我已經看到了優化視圖的一些潛力,但這似乎是一個範圍有限的解決方案 - 儘管我不確定我的通用解決方案是什麼。例如,如何手動調用gc.collect()或gc.set_threshold()?
在垃圾收集器本身的工作原理方面:
難道我理解正確的話,一個對象總是移動到下一代,如果掃描看着它確定引用它有不是循環的,但實際上可以追溯到根對象。
如果gc進行第1代掃描並發現第2代內的對象所引用的對象,會發生什麼情況;它是否遵循第二代內部的關係,還是在分析情況之前等待第二代掃描發生?
當使用gc.DEBUG_STATS時,我主要關心「每一代中的對象」信息;然而,我不斷收到數百個「gc:0.0740秒過去了」,「gc:1258233035.9370s過去了。」消息;他們完全不方便 - 他們需要花費相當多的時間才能印出來,而且他們使得有趣的事情難以發現。有沒有辦法擺脫它們?
我不假設有一種方法可以按代生成gc.get_objects(),例如只從第2代檢索對象,例如?
+1提及設置DEBUG = False因此Django不會記錄所有的SQL查詢。 – Kekoa
哇,什麼Django的心理形象吃多少食物的方式 –