一個隱秘在角度的bug
前幾天一直被一個bug 困擾著, 代碼是一段requests請求url讀取html內(nèi)容的代碼,每次程序啟動大約運(yùn)行幾十個小時后,就開始報錯MemoryError。
把核心代碼提出來就一行代碼
r = requests.get('https://xxxx')
錯誤堆棧日志大概是這樣的
File "***.py", line 644, in post
r = s.post(url, data=content, params=params, files=files, headers=headers)
File "/usr/local/lib/python3.7/dist-packages/requests/sessions.py", line 424, in post
return self.request('POST', url, data=data, **kwargs)
File "/usr/local/lib/python3.7/dist-packages/requests_cache/core.py", line 110, in request
hooks, stream, verify, cert)
File "/usr/local/lib/python3.7/dist-packages/requests/sessions.py", line 348, in request
prep = self.prepare_request(req)
File "/usr/local/lib/python3.7/dist-packages/requests/sessions.py", line 286, in prepare_request
hooks=merge_hooks(request.hooks, self.hooks),
File "/usr/local/lib/python3.7/dist-packages/requests/models.py", line 289, in prepare
self.prepare_body(data, files)
File "/usr/local/lib/python32.7/dist-packages/requests/models.py", line 426, in prepare_body
(body, content_type) = self._encode_files(files, data)
File "/usr/local/lib/python3.7/dist-packages/requests/models.py", line 144, in _encode_files
body, content_type = encode_multipart_formdata(new_fields)
File "/usr/local/lib/python3.7/dist-packages/requests/packages/urllib3/filepost.py", line 101, in encode_multipart_formdata
return body.getvalue(), content_type
MemoryError
錯誤提示很明顯,應(yīng)該是內(nèi)存不足導(dǎo)致的
平時很少會遇到這個問題,估計你們也不怎么會遇到,除非確實是處理超大文件
我的排查思路是這樣的
首先確定是不是我的系統(tǒng)真的內(nèi)存不足了,然后就跑過去查看任務(wù)管理器,16G的內(nèi)存,才使用了60%多點,應(yīng)該說內(nèi)存還是非常充足的。

接著又去分析是不是請求返回的數(shù)據(jù)非常大導(dǎo)致的,驗證后不存在這個問題,因為請求的最大數(shù)據(jù)最大也就幾百KB。
然后又把程序稍微優(yōu)化了一下,看看是不是每次請求完之后資源沒釋放
with requests.Session() as s:
s.get('https://xxxx')
改成with上下文處理,請求結(jié)束后會自動關(guān)閉請求連接。
經(jīng)過一段時間的觀察,然而并沒什么卵用,問題依然存在
這個時候用Google、StackOverflow也找到合適的答案。
按照武俠小說劇情發(fā)展的話,在你最孤獨最無助時,主角就會有靈光乍現(xiàn)的時刻。
無意間發(fā)現(xiàn)系統(tǒng)安裝的Python3.7 是32位,當(dāng)初安裝的時候也沒注意太多。

32位系統(tǒng)使用32位地址線的最大尋址空間為2的32次方bytes,計算后即4294967296 Bytes,也就是我們常說的4096MB,32位地址線的尋址空間封頂即為4GB。雖然我的系統(tǒng)是64位,但是python這個程序安裝的是32位,通常應(yīng)用程序占用內(nèi)存不能超過2GB以上,如果超過就會發(fā)生內(nèi)存溢出現(xiàn)象。
最后把Python升級到64位問題完美解決,持續(xù)運(yùn)行了幾天依然沒有報錯。

總結(jié):
很多時候,我們遇到某些看似像靈異事件的bug,其實都是我們在平時編碼過程中的沒注意細(xì)節(jié)埋下的坑,魔鬼在細(xì)節(jié)。
