電腦最大內存4g
十年前512M內存的電腦用得飛快,而現在4G的還不夠用,是因為軟件太大還是程序優化的程度比以前降低了,抑或是硬件的問題? 我們一起思考下!先看幾張圖這是10年前的WindowsWindows Vist...
2025.07.03COPYRIGHT ? 2023
粵ICP備2021108052號
郵箱:611661226@qq.com
留言給我某線上運行的C++服務,在一臺機器上訪問失敗率很高,監控顯示如下圖:
登錄問題機器,發現該服務占用的內存高達30G,這是不正常的,疑似內存泄露。為了減少服務運行損失,先把該機器摘掉,再進行問題分析。
從現象上來看,服務的失敗率,主要原因是內存泄露,導致內存占用高,從而影響到服務的正常運行。內存泄露大體可以分為兩種:
1、申請了內存,沒有釋放,代碼實現上的bug。
2、全局(或常駐內存)變量,因為某種原因申請了大量的內存,由于其生命周期未結束,暫時還沒有釋放。這可能是一種設計上的bug。
于是,查看了線上其他機器,并沒有發現內存占用過高的情況,同時,也沒有發現內存持續增長。從這個方面來看,更傾向于第二種情況,或者是機器自身問題。查看了問題機器上,該服務的運行日志及系統日志,并沒有發現明顯的問題。
因此,需要從服務進程去定位問題,分析步驟:
為了不影響線上業務,需要快速恢復服務。于是,先使用gcore命令將運行的進程dump下來,保存現場,命令如下:
# gcore 24564(進程pid)
執行命令后,會在當前目錄下生成一個該進程的core dump文件了。接著,重啟服務后,觀察了一段時間,并沒有發現內存持續增長。
使用gdb調試剛才dump下來的core dump文件,查看進程中內存分配情況,如下:
(gdb) maintenance info sections………… 0x7f8c18000000->0x7f8c1c000000 at 0x3af828854: load398 ALLOC LOAD HAS_CONTENTS0x7f8c1c000000->0x7f8c1ffff000 at 0x3b3828854: load399 ALLOC LOAD HAS_CONTENTS0x7f8c1ffff000->0x7f8c20000000 at 0x3b7827854: load400 ALLOC LOAD READONLY HAS_CONTENTS0x7f8c20000000->0x7f8c23fe0000 at 0x3b7828854: load401 ALLOC LOAD HAS_CONTENTS0x7f8c23fe0000->0x7f8c24000000 at 0x3bb808854: load402 ALLOC LOAD READONLY HAS_CONTENTS0x7f8c28000000->0x7f8c2bffa000 at 0x3bb828854: load403 ALLOC LOAD HAS_CONTENTS0x7f8c2bffa000->0x7f8c2c000000 at 0x3bf822854: load404 ALLOC LOAD READONLY HAS_CONTENTS0x7f8c30000000->0x7f8c34000000 at 0x3bf828854: load405 ALLOC LOAD HAS_CONTENTS0x7f8c38000000->0x7f8c3c000000 at 0x3c3828854: load406 ALLOC LOAD HAS_CONTENTS0x7f8c40000000->0x7f8c43ffe000 at 0x3c7828854: load407 ALLOC LOAD HAS_CONTENTS0x7f8c43ffe000->0x7f8c44000000 at 0x3cb826854: load408 ALLOC LOAD READONLY HAS_CONTENTS………………
可以看到分配了大量的內存,猜測這些內存塊就是泄露的。為了定位到內存泄露的代碼,嘗試查看了這些幾個內存塊中的內容,看看是否能看到一些字符串或者有規律的內容,但是,并沒有發現有價值的線索。
在gdb中,使用info variables命令,可以將進程中的全局變量,打印出來。但是由于引用了很多的第三方庫等,可能輸出內容會比較多。因此,可以考慮通過腳本進行過濾,重點排查該服務相關的變量。這里并不是說,第三方庫不會有問題,但是,目前嫌疑最大的仍然是我們寫的代碼。針對篩選出來的全局變量,進行排查。重點檢查的內容有,數組、vector、map等各種容器大小。
在排查中,發現其中一個全局變量中queue對象的_M_map_size = 10485758,這是不正常的。
(gdb) p Singleton::instance_->query_queue_$2 = {queue_ = {c = {, std::allocator<char> >, std::allocator, std::allocator<char> > > >> = {_M_impl = {, std::allocator<char> > >> = {<__gnu_cxx::new_allocator, std::allocator<char> > >> = {}, },members of std::_Deque_base, std::allocator<char> >, std::allocator, std::allocator<char> > > >::_Deque_impl:_M_map = 0x7f8ac2fff010,_M_map_size = 10485758,_M_start = {_M_cur = 0x7f8c08040f68,_M_first = 0x7f8c08040d70,_M_last = 0x7f8c08040f70,_M_node = 0x7f8ac5c17e80},_M_finish = {_M_cur = 0x7f903532af30,_M_first = 0x7f903532ade0,_M_last = 0x7f903532afe0,_M_node = 0x7f8ac7822960}}}, }},}
可以看到,這是一個使用std::queue
根據調試信息,可以計算出:
map中node個數為:(0x7f8ac7822960-0x7f8ac5c17e80)/8=3675484個。
每個node對應一個緩沖區,緩沖區的大小為0x7f8c08040f70 - 0x7f8c08040d70 = 512字節。
由于地址占8字節,因此一個緩沖區中有:512/8=64個元素。
當前隊列中,元素總數為:3675484*64=235230976。
通過查看內存中字符串占的內存,可以發現,緩存的字符串占用內存平均在100字符左右,計算這部分內存為:(235230976*100)/(1024*1024*1024.0)=21.9G。
與泄露的內存大小基本符合?;究梢哉J為,是由于隊列中緩存元素過多,導致了服務的內存泄露。
通過閱讀源碼,可以看到該變量的所在模塊的功能是:實現一個帶過期時間的緩存。具體實現邏輯是:每次請求從該緩存模塊中取得一個key的緩存值,若該key已經在緩存中,且未過期,則直接返回對應的緩存值。若沒有在緩存中(或已經過期),該將該key寫入到一個隊列中,由另一個更新線程去后臺查詢更新該key對應的緩存。
造成隊列中數據大量堆積的可能原因是,某一時刻,更新線程查詢后臺時,出現了延時,引發堆積。由于訪問量很大,且過期時間設定得較短,再加上,隊列中重復key也并不會去重。因此,只要發生抖動,就會發生大量堆積,最終導致內存激增,服務異常。
為了驗證問題,重新查看運行日志,確實能找到查詢后臺服務失敗的相關日志,只是報錯日志量不大,在最開始查看日志時,并未引起注意。至此,基本可以確認該問題。
對于線上問題處理來說,一般的原則是,先快速恢復服務,后定位問題。比如,因為新功能上線,導致服務異常,首先做的是代碼回滾。本文中通過gcore將進程的內存dump下來,能較好地保存現場,同時,重啟進程,恢復服務。因為已經保存了進程當時的內存狀態,可以給分析問題提供較大地便利和更多地依據。
內存泄露的排查方法和工具有很多,如何在不重啟服務、不重新編譯、最小性能影響等方式下,快速定位到進程內存泄露點,仍有一定的挑戰。
十年前512M內存的電腦用得飛快,而現在4G的還不夠用,是因為軟件太大還是程序優化的程度比以前降低了,抑或是硬件的問題? 我們一起思考下!先看幾張圖這是10年前的WindowsWindows Vist...
2025.07.03電腦常常遇到“內存不足”?加了內存條之后依然頻繁提醒,這究竟是怎么回事?今日,英特爾官方在社交平臺為粉絲解答了該問題。英特爾表示“很可能某個程序的代碼錯誤導致電腦內存溢出,之前被占用的內存無法釋放???..
2025.07.03關于電腦的虛擬內存,是個老生常談的問題了。說實話,對于如今電腦的硬件水平來說,虛擬內存設置能起到的作用并不大。不過,考慮到很多朋友可能仍有在用低配置老電腦的,所以就補充下這塊的內容。所謂虛擬內存,是計...
2025.07.03正值雙·11大促,惠普戰66五代超值好價熱賣中,銳龍版3999元起步,酷睿版4299元起步,大內存版4799元起,同時參加曬單評論活動的朋友,還可獲贈原裝大禮包(含背包,鼠標,和筆記本支架),性價比絕...
2025.07.03微信真的太吃內存了,夸張到什么程度呢?我打開手機的存儲空間看了一眼,其他APP一年下來包緩存數據也就1個G左右,占用內存多一些的也就3個G,大型的游戲也不過12個G左右,而微信竟占了22個G!而且隨著...
2025.07.03