簡體   English   中英

Python 程序占用內存

[英]Python program eating up RAM

我寫了一個小程序來使用 MinimalModbus 通過串口收集數據。 數據被轉儲到一個 CSV 文件中。 我已經閱讀了關於 SO 和其他地方的幾篇文章。 提到的幾件事是:

  1. 盡可能使用惰性求值(xrange 而不是 range)
  2. 刪除未使用的大對象
  3. 使用子進程並在它們死亡時由操作系統釋放內存

該腳本是在github 這里 我還使用腳本定期將這些文件上傳到服務器。 這兩個腳本都相當簡單。 系統上也沒有其他東西在運行,因此我覺得這兩個系統只會發生內存占用。 解決這個問題的最佳方法是什么。 我不是最願意采用子流程路線。

更多信息:

  1. 數據收集在 Raspberry Pi(512 MB RAM)上
  2. Python版本:2.7
  3. RAM完全使用大約需要3-4天,然后RaspberryPi凍結

我按照指南找出了消耗 RAM 的前 20 個程序。

$ ps aux | awk '{print $2, $4, $11}' | sort -k2rn | head -n 20
12434 2.2 python
12338 1.2 python
2578 0.8 /usr/sbin/console-kit-daemon
30259 0.7 sshd:
30283 0.7 -bash
1772 0.6 /usr/sbin/rsyslogd
2645 0.6 /usr/lib/policykit-1/polkitd
2146 0.5 dhclient
1911 0.4 /usr/sbin/ntpd
12337 0.3 sudo
12433 0.3 sudo
1981 0.3 sudo
30280 0.3 sshd:
154 0.2 udevd
16994 0.2 /usr/sbin/sshd
17006 0.2 ps
1875 0.2 /usr/bin/dbus-daemon
278 0.2 udevd
290 0.2 udevd
1 0.1 init

因此,這兩個 Python 進程占用了一些 RAM,但與消耗的總 RAM 相比,這非常小。 以下是 free 命令的輸出。

pi@raspberrypi ~ $ free -m
             total       used       free     shared    buffers     cached
Mem:           438        414         23          0         45        320
-/+ buffers/cache:         48        389
Swap:           99          0         99

以下是 top 命令的輸出。

Tasks:  69 total,   1 running,  68 sleeping,   0 stopped,   0 zombie
%Cpu(s): 66.9 us,  5.0 sy,  0.0 ni, 18.1 id,  0.0 wa,  0.0 hi, 10.0 si,  0.0 st
KiB Mem:    448776 total,   429160 used,    19616 free,    47016 buffers
KiB Swap:   102396 total,        0 used,   102396 free,   332288 cached

PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND           
12338 root    20   0 10156 5644 2384 S  69.8  1.3   3059:31 python            
26039 root    20   0     0    0    0 S   1.6  0.0   0:02.71 kworker/0:1       
26863 pi      20   0  4664 1356 1028 R   1.3  0.3   0:00.12 top               
1982 root     20   0  1752  516  448 S   0.3  0.1   1:08.36 sh                
1985 root     20   0  1692  552  460 S   0.3  0.1   5:15.16 startpar          
1 root        20   0  2144  728  620 S   0.0  0.2   0:17.43 init              
2 root        20   0     0    0    0 S   0.0  0.0   0:00.14 kthreadd          
3 root        20   0     0    0    0 S   0.0  0.0   0:13.20 ksoftirqd/0       
5 root         0 -20     0    0    0 S   0.0  0.0   0:00.00 kworker/0:0H      
7 root         0 -20     0    0    0 S   0.0  0.0   0:00.00 kworker/u:0H      
8 root         0 -20     0    0    0 S   0.0  0.0   0:00.00 khelper           
9 root        20   0     0    0    0 S   0.0  0.0   0:00.00 kdevtmpfs         
10 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 netns             
12 root      20   0     0    0    0 S   0.0  0.0   0:00.06 bdi-default       
13 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 kblockd 

編輯 2

正如第一個答案中所建議的,我決定查看日志文件。 我查看了 syslog,下面是 tail 的結果。

May 19 10:03:26 raspberrypi wpa_supplicant[7065]: wlan0: Failed to initialize driver    interface
May 19 10:03:49 raspberrypi wpa_supplicant[7157]: nl80211: 'nl80211' generic netlink not found
May 19 10:03:49 raspberrypi wpa_supplicant[7157]: Failed to initialize driver 'nl80211'
May 19 10:03:49 raspberrypi wpa_supplicant[7157]: rfkill: Cannot open RFKILL control device
May 19 10:03:49 raspberrypi wpa_supplicant[7157]: Could not read interface wlan0 flags: No such device

這些消息正在填滿日志文件,並且每秒都會出現。 有趣的部分是我使用的是以太網而不是 WiFi。

因此,現在還不清楚 RAM 去了哪里?

大多數 RAM 可用於應用程序,因為它用於緩沖區和緩存。 查看“-/+ buffers/cache:”行以查看實際使用/空閑的 RAM 量。 可以在此處找到解釋。

要驗證 Python 是否正在泄漏內存,請隨時間監視 Python 的 RSS 大小(或 %mem)。 例如,編寫一個每隔幾個小時從 cron 作業調用的 shell 腳本,以將ps命令鏈的輸出和free命令的輸出附加到文件中。

如果您發現 Python 進程正在泄漏內存,您可以執行以下操作:

  • 修改您的腳本使其在 24 小時后退出,並使用例如 cron 作業重新啟動它(最簡單的方法)。
  • 深入了解 Python 本身,尤其是您正在使用的擴展模塊。 使用gc模塊來監控和影響內存使用。 例如,您可以定期調用gc.count()來監視標記為收集的對象的數量。 您可以顯式調用gc.collect()並查看是否可以減少內存使用。 您還可以修改收集閾值。

如果 Python 的 RAM 使用不隨時間增加,則它可能是另一個守護程序程序。 我上面提到的內存記錄腳本應該告訴你它是哪一個。

您的計算機死機也可能是另一個原因。 查看 Linux 日志文件以獲取線索。

編輯:由於您有wpa_supplicant填寫日志文件,您應該檢查文件系統的狀態。 完整的文件系統可能會導致系統掛起。 如果您不使用無線接口,請將其禁用。

import gc
gc.collect()

為我工作。 這是摘自 Roland Smith 接受的答案,我認為未來的搜索者指出它作為答案很有用。

也許為時已晚,但我在 Droplet ubuntu 服務器上遇到了同樣的問題。 每 15 分鍾有一個運行 python 腳本的 cron 作業。 三天后,我的記憶力耗盡了。 所以我決定通過 cron 每 x 分鍾殺死一次 python,因為我沒有找到解決方案。

我用過這個:

pkill -f 腳本名.py

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM