最近工作中慢慢開始用python協(xié)程相關(guān)的東西,所以用到了一些相關(guān)模塊,如aiohttp, aiomysql, aioredis等,用的過程中也碰到的很多問題,這里整理了一次內(nèi)存泄漏的問題
通常我們寫python程序的時(shí)候也很少關(guān)注內(nèi)存這個(gè)問題(當(dāng)然可能我的能力還有待提升),可能寫c和c++的朋友會(huì)更多的考慮這個(gè)問題,但是一旦我們的python程序出現(xiàn)了
內(nèi)存泄漏的問題,也將是一件非常麻煩的事情了,而最近的一次代碼中也碰到了這個(gè)問題,不過好在最后內(nèi)存溢出不是我代碼的問題,而是所用到的一個(gè)包出現(xiàn)了內(nèi)存的問題,下面我通過一個(gè)簡單的代碼模擬出內(nèi)存的問題,然后也會(huì)將解決的過程描述一下,希望能幫助到遇到同樣問題的朋友。
其實(shí)這次主要是在使用aiohttp寫一個(gè)接口的時(shí)候出現(xiàn)的問題,其實(shí)復(fù)現(xiàn)出問題非常容易,我們實(shí)現(xiàn)一個(gè)簡單的接受post請求接口的服務(wù)端,然后實(shí)現(xiàn)一個(gè)并發(fā)的客戶端來訪問這個(gè)接口,來查看內(nèi)存的情況
注意: 這個(gè)問題是在一個(gè)包的特定版本出現(xiàn)的:multidict==4.5.1,我在整理這個(gè)文章2個(gè)小時(shí)前作者已經(jīng)修復(fù)了這個(gè)問題發(fā)布了4.5.2版本,已經(jīng)修復(fù)了內(nèi)存的問題,并且我也進(jìn)行了測試驗(yàn)證
服務(wù)端代碼:
from aiohttp import webasync def hello(request): return web.json_response(await request.json())app = web.Application()app.add_routes([web.post('/', hello)])web.run_app(app)客戶端代碼:
import asyncioimport aiohttpasync 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()因?yàn)槲业拇a是在linux上跑的,或者mac上我們都可以通過htop非常方面的實(shí)時(shí)查看我們程序內(nèi)存的占用情況,我們先將服務(wù)端啟動(dòng),查看一下我們此時(shí)的內(nèi)存情況可以看到占用的
非常少,當(dāng)我們打開客戶端之后,再次觀察我們可以看到內(nèi)存不斷增長,及時(shí)我們客戶端運(yùn)行完畢內(nèi)存也不會(huì)降低。

當(dāng)客戶端結(jié)束之后的內(nèi)存:
如果客戶端不停止的話內(nèi)存會(huì)一直漲,最后的結(jié)果就是把你的系統(tǒng)內(nèi)存吃完,然后被系統(tǒng)殺掉你的進(jìn)程。

像上面的例子是一個(gè)非常簡單的程序,不復(fù)雜我們也并沒有做上面復(fù)雜的操作就是一個(gè)簡單的接受post請求的服務(wù)端,但是如果是在實(shí)際的項(xiàng)目中我們可能會(huì)寫非常復(fù)雜的業(yè)務(wù)邏輯,那到時(shí)候我們又如何找到是哪里導(dǎo)致的內(nèi)存問題,當(dāng)我碰到這個(gè)問題的時(shí)候,其實(shí)我和很多接觸python不久的人差不多,也是不知道怎么查這種問題,各種百度各種查,也找到了好多推薦的工具,memory_profiler庫,objgraph庫,graphviz工具,但是都沒有幫助我迅速的找到問題點(diǎn)在哪里,最后看到標(biāo)準(zhǔn)庫中的tracemalloc,地址:https://docs.python.org/3/library/tracemalloc.html
新聞熱點(diǎn)
疑難解答
圖片精選