這篇文章將為大家詳細講解有關(guān)python中如何解決內(nèi)存泄漏問題,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
在福山等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站建設(shè)、網(wǎng)站設(shè)計 網(wǎng)站設(shè)計制作按需設(shè)計網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站設(shè)計,營銷型網(wǎng)站,成都外貿(mào)網(wǎng)站制作,福山網(wǎng)站建設(shè)費用合理。一、復(fù)現(xiàn)問題其實這次主要是在使用aiohttp寫一個接口的時候出現(xiàn)的問題,其實復(fù)現(xiàn)出問題非常容易,我們實現(xiàn)一個簡單的接受post請求接口的服務(wù)端,然后實現(xiàn)一個并發(fā)的客戶端來訪問這個接口,來查看內(nèi)存的情況
注意: 這個問題是在一個包的特定版本出現(xiàn)的:multidict==4.5.1,
我在整理這個文章2個小時前作者已經(jīng)修復(fù)了這個問題發(fā)布了4.5.2版本,已經(jīng)修復(fù)了內(nèi)存的問題,并且我也進行了測試驗證
服務(wù)端代碼:
from aiohttp import web async def hello(request): return web.json_response(await request.json()) app = web.Application() app.add_routes([web.post('/', hello)]) web.run_app(app)
客戶端代碼:
import asyncio import aiohttp async def foo(times): data = {'foo': 1} async with aiohttp.ClientSession() as session: for x in range(times): resp = await session.post('http://localhost:8080', json=data) if not x % 100: print(await resp.json()) loop = asyncio.get_event_loop() loop.run_until_complete(foo(100000)) loop.close()
因為我的代碼是在linux上跑的,或者mac上我們都可以通過htop非常方面的實時查看我們程序內(nèi)存的占用情況,我們先將服務(wù)端啟動,查看一下我們此時的內(nèi)存情況可以看到占用的
非常少,當我們打開客戶端之后,再次觀察我們可以看到內(nèi)存不斷增長,及時我們客戶端運行完畢內(nèi)存也不會降低。
當客戶端結(jié)束之后的內(nèi)存:
如果客戶端不停止的話內(nèi)存會一直漲,最后的結(jié)果就是把你的系統(tǒng)內(nèi)存吃完,然后被系統(tǒng)殺掉你的進程。
二、解決內(nèi)存泄漏的過程像上面的例子是一個非常簡單的程序,不復(fù)雜我們也并沒有做上面復(fù)雜的操作就是一個簡單的接受post請求的服務(wù)端,但是如果是在實際的項目中我們可能會寫非常復(fù)雜的業(yè)務(wù)邏輯,那到時候我們又如何找到是哪里導(dǎo)致的內(nèi)存問題,當我碰到這個問題的時候,其實我和很多接觸python不久的人差不多,也是不知道怎么查這種問題,各種百度各種查,也找到了好多推薦的工具,memory_profiler庫,objgraph庫,graphviz工具,但是都沒有幫助我迅速的找到問題點在哪里,最后看到標準庫中的tracemalloc,地址:https://docs.python.org/3/library/tracemalloc.html
通過這個包很快幫我找到了內(nèi)存泄漏的地方
接下來按照官網(wǎng)的方法我將代碼進行改寫,來測試到底哪里的問題導(dǎo)致的內(nèi)存泄漏,更改后的服務(wù)端代碼為:
from aiohttp import web import tracemalloc async def hello(request): return web.json_response(await request.json()) async def get_info(request): snapshot2 = tracemalloc.take_snapshot() top_stats = snapshot2.compare_to(snapshot1, 'lineno') print(top_stats) return web.Response(text="ok") if __name__ == '__main__': app = web.Application() app.add_routes( [ web.post('/', hello), web.get("/get_info", get_info) ] ) tracemalloc.start() snapshot1 = tracemalloc.take_snapshot() web.run_app(app)
注意print(top_stats)這行打印的結(jié)果最后要關(guān)注
其實這里就是新增加了一個路由get_info, 我們啟動服務(wù)端之后開啟客戶端,當我們客戶端運行完畢之后,可以看到內(nèi)存已經(jīng)漲上去了,并且沒有不會釋放,這個時候,可以直接通過瀏覽器訪問get_info這個路由看看print打印的內(nèi)容,這里將會打印出你程序運行到這個時候那一行的代碼內(nèi)存增長的比較多,進行一次排序,前面的幾個其實都是需要你關(guān)注的,因為這里數(shù)據(jù)較多,我就只打印如下前幾個數(shù)據(jù)
,)> size=116500672 (+116500672) count=300004 (+300004)>, ,)> size=11400000 (+11400000) count=200000 (+200000)>, ,)> size=8000000 (+8000000) count=100000 (+100000)>, ,)> size=5500000 (+5500000) count=100000 (+100000)>, ,)> size=5300608 (+5300608) count=100001 (+100001)>,
我們拿第一行來說,我們可以非常清楚的指導(dǎo)web_response的56行代碼導(dǎo)致內(nèi)存增長的最多,當然如果是我們復(fù)雜的項目也可以通過類似的方法,這樣就可以非??旖莸恼业轿覀兇a中哪些地方會造成內(nèi)存溢出,便于排查問題,我們點進去看看這行代碼:
我們找到最終行,這個時候我們大致就可以看出哪里的問題了,我們接著看 CIMultiDict
class CIMultiDict(MultiDict): def _title(self, key): return key.title()
我們可以看到這個它繼承 MultiDict 其實這里我們已經(jīng)應(yīng)該知道問題就是處在這個MultiDict上了
而這個最終其實最終就是MultiDict這個包,問題出在了這個包上,這個項目是在這里維護的:https://github.com/aio-libs/multidict
查看這個包的時候看到了,果然有人和我遇到了同樣的問題,問題就是出在這里了,已經(jīng)有人提交了bug
https://github.com/aio-libs/multidict/issues/307
不過不得不說國外的程序員真的是熱愛自己的職業(yè),很快這個問題得到了aio-libs小組中人的回應(yīng),問題也在我整理這個博客的時候被修復(fù)了,在最新的版本:4.5.2中已經(jīng)測試沒有內(nèi)存泄漏的問題
關(guān)于“python中如何解決內(nèi)存泄漏問題”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。