1. 程式人生 > >記錄一次kernel記憶體洩漏的查詢定位過程

記錄一次kernel記憶體洩漏的查詢定位過程

Bug描述:壓力測試一個小工程時發現記憶體逐漸減少,10個小時後出現OOM

Bug定位過程:

  • 對整個工程模組進行分解,逐步縮小範圍,由於整個工程包括幾個相對獨立的小模組,而整個工程採用單程序多執行緒的模型,導致進行分解時,要特別注意相互之間的耦合,只能逐步分離各個模組,執行測試(這裡如果採用多程序模型,定位會更快一些,一個完整的功能,放在一個程序和多程序中,多程序天然的將功能細化了,定位問題,範圍更小)
  • 在經過一段折磨人的拆分過程後,最後把問題定位到整個工程中一個小模組功能內。在對該模組進行了反覆的程式碼review後,沒有發現什麼異常,甚至沒有記憶體申請的操作。
  • 程式碼層面沒有找到突破的情況下,重新通過各種命令查看了記憶體狀態,由於在此之前一直通過free命令檢視記憶體,發現長時間後free命令輸出的可用記憶體在逐漸減少,但忽略了一點:通過top命令單獨檢視模組程序佔用的記憶體時,該程序的rss段一直保持穩定,沒有大幅度增長。
  • 基於前一步的發現,懷疑是kernel的記憶體有洩漏,檢視/proc/meminfo發現一個疑點:slab記憶體佔用很高,且SUnreclaim的slab一直在增加,此時基本確定kernel記憶體洩漏。
  • 通過kmemleak對核心記憶體進行了分析,定位在到一個函式介面中:
char *wr_pr_debug_begin(u8 const *data, u32 len, char *string)
{
    int ii;
    string = kmalloc(len * 2 + 1, GFP_KERNEL);
    for (ii = 0; ii < len; ii++)
        sprintf
(&string[ii * 2], "%02X", data[ii]); string[len * 2] = 0; return string; } char *wr_pr_debug_end(char *string) { kfree(string); return ""; } void test() { char *read = 0; pr_debug("%s RD%02X%02X%02X -> %s%s\n", st->hw->name, i2c_addr, reg, length, wr_pr_debug_begin(data, length
, read), wr_pr_debug_end(read)); }

一眼可能不容易看出上面的有什麼問題,有kmalloc,有kfree啊,好像成對出現的。
考驗基本功的時候到了,熟悉函式呼叫傳參的人應該會知道編譯器一般對引數的處理採用堆疊的方式,是一個先進後出的過程,這樣引數的執行一般是逆序的(由於編譯器實現的不同,這個過程不是確定的),這樣kfree會在kmalloc之前執行,導致每次執行都會洩漏一點記憶體。上面是一個debug輸出,暫時註釋掉後壓測,問題解決,記憶體保持穩定。

總結:整個定位過程其實比較簡單,如果第一步看下/proc/meminfo可能會更快的定位問題(由於這個kernel driver是“大廠”提供,以為不會出問題,一直從上層的角度去找問題,所以沒有太關注kernel相關記憶體的使用),導致記憶體洩漏的原因也很簡單,出現這種問題的原因,首先編寫者的基本功一般,更主要的原因是編寫者出於“炫技”的方式去寫了這段程式碼,如果老老實實封裝一個debug函式,按照正常順序呼叫也就沒有問題了,而且這種每次列印進行kmalloc的方式,對效能也是有些影響的。總之基本功還是很重要,而且不要駕馭自己駕馭不了的編碼方式。

相關推薦

記錄kernel記憶體洩漏查詢定位過程

Bug描述:壓力測試一個小工程時發現記憶體逐漸減少,10個小時後出現OOM Bug定位過程: 對整個工程模組進行分解,逐步縮小範圍,由於整個工程包括幾個相對獨立的小模組,而整個工程採用單程序多執行緒的模型,導致進行分解時,要特別注意相互之間的耦合,只能逐步

記憶體洩漏問題定位過程與分析

現場: 邏輯server伺服器處理能力驟降, 客戶端請求大量失敗.  邏輯server的統計資料顯示,請求量略有增長(客戶端重試的結果), log內容顯示訪問外部介面有一定失敗. 分析: 第一反應是外部介面失敗導致程序處理堵塞,大量請求被堵塞後丟棄導致客戶端重試.

線上記憶體洩漏的問題排查

上線了好久的專案今天突然出現cpu到達100% 的情況,先將專案緊急重啟,恢復正常後登入伺服器排查gc日誌,發現存在記憶體洩漏的情況。 top命令檢視程序情況,top -Hp pid檢視執行緒,再jstack匯出日誌。過程匆忙,忘了截圖 搜尋jsatck日誌看到許多執行緒阻塞在這一行程式碼 基本可以

python 記憶體洩漏解決過程

最近工作中慢慢開始用python協程相關的東西,所以用到了一些相關模組,如aiohttp, aiomysql, aioredis等,用的過程中也碰到的很多問題,這裡整理了一次記憶體洩漏的問題 通常我們寫python程式的時候也很少關注記憶體這個問題(當然可能我的能力還有待提升),可能寫c和c++的朋友會更多

Java 記憶體洩漏排查過程,漲姿勢

人人都會犯錯,但一些錯誤是如此的荒謬,我想不通怎麼會有人犯這種錯誤。更沒想到的是,這種事竟發生在了我們身上。當然,這種東西只有事後才能發現真相。接下來,我將講述一系列最近在我們一個應用上犯過的這種錯誤。最有意思的是,一開始的跡象揭示的問題,與實際發生的問題完全不同。 在一個淒涼的午夜 午夜剛過,我就被一條

記錄系統記憶體消耗太大的問題排查

      系統架構採用了spring cloud,資料庫架構在mycat上,系統大體的架構如下: 未做前後端分離。前端採用jsp,ui做前端彙總,存放jsp。controller被ui引用,manager做邏輯層,microservice做微服務層,controlle

記錄jvm記憶體洩露的問題

  前些天,運維告訴我剛上線的java服務佔用CPU過高。        以下是發現解決問題的具體流程。    1:通過#top命令檢視,我的java服務確實把CPU幾乎佔滿了,如圖         可看到18400這個程序CPU佔用達到了

原創 記錄線上Mysql慢查詢問題排查過程

背景 前段時間收到運維反饋,線上Mysql資料庫凌晨時候出現慢查詢的報警,並把原始sql發了過來: --去除了業務含義的sql update test_user set a=1 where id=1; 表資料量200W左右,不是很大,而且是根據主鍵更新。 問題排查 排查Mysql資料庫 我看到sql後第一

記錄concurrent mode failure問題排查過程以及解決思路

tails only cnblogs 策略 executor red execute incr run 背景:後臺定時任務腳本每天淩晨5點30會執行一個批量掃庫做業務的邏輯。 gc錯誤日誌: 2017-07-05T05:30:54.408+0800: 518534

記錄使用UnifOfWork改造項目的過程

距離 創建 值對象 領取 模式 ram scope 移動端 技術 一、前言   UnifOfWork模式,一般稱為“工作單元”模式,是DDD(Domain-Driven Design,領域驅動設計)的一個組成部分,用於在應用服務方法中,控制一個應用服務方法的所有數據庫操作,

記錄抽獎超發排查問題過程

緩存控制 緩存 騰訊雲 領導 通過 redis 不知道 服務 更新 接到運營方提出的bug,說是移動端優惠券超發,通過拉取線上數據,確實存在超發現象,而且恰好是設定的兩倍。 通過在測試和仿真環境新建一個活動頁面添加優惠券進行測試,又不會出現超發現象,想到

記錄redis數據庫搭建過程並詳細說明配置

保存 hashing sys 不能 led active 成功 ber cto redis.conf配置文件詳解 Redis默認不是以守護進程的方式運行,可以通過該配置項修改,使用yes啟用守護進程daemonize no 當Redis以守護進程方式運行時,Redis默

[hi3518] 記錄Hi3518E新添sensor的過程

使用的sensor是海思列表沒有支援的SC2235,主要需要了解到這個sensor的配置已經地址(需要向sensor原廠要驅動sc2235_cmos.c sc2235_sensor_ctl.c  sc2235_1080p_line.ini vpss_attr_2235.c)編譯為.so .

記錄在安裝雙系統的過程(先有debian, 後加windows 8.1)

突破的難題:  如何在一整個根目錄的分割槽中切出來一半用於安裝windows8.1呢?     當初安裝debian系統時, 由於腦殘,直接把整個500G的硬碟分給了根目錄 /  ,所以整個磁碟就TMD的一個主分割槽;   現在想再安裝一個window 8.1系統,太讓我為難了,幾乎找了所有資料,就是沒有找

記錄mybatis查詢返回為空資料庫卻能查詢到資料的經歷

   昨晚上測試人員給發了一條測試資料,說是根據這條資料介面返回資訊為空。之後根據給的資訊去資料庫查詢了下,明明是有資料的。但是用mybatis就是查詢不出來。奇了怪了,自己測試的資料都能查詢出來,為何這條資料就是沒有那?查詢條件就是 主鍵+狀態值而已,沒有多餘的查詢。   &

記錄線上關於socket超時問題的定位

現象:應用程式就是簡單的spring+cxf組成的系統,系統上線執行後發現執行一段時間之後就發現請求可以進來卻得不到處理,cxf的處理過程是建立一個執行緒,並提交到執行緒池去執行.。 import java.io.PrintWriter; import javax.servlet.Asyn

記錄查詢log的經歷

一大早發現生產資料庫的基礎資料被刪除。 由於每天都做了差異備份,而且是基礎資料,這樣資料就不會擔心找不回來。 首先通過每天的差異本分檔案進行檢視資料丟失的大概時間,查到資料丟失是在17晚上備份過後18丟失的。 然後找18號的資料庫執行記錄 貼上語句: SELECT ST.text AS '執

mysql去重查詢與刪除重複記錄

查詢: select *,id,count(*) as count from artist group by id having count>1; 刪除(刪除order_id值大的): delete from artist where id in( SELECT * from

通過Memory Analyzer分析記憶體洩漏的解決過程

狀況描述: 最近專案新打的版本,過不了多長時間,專案就會掛掉。狀況就是處於一種假死的狀態。索引查詢都很慢,幾乎進行不了任何操作,慢慢卡死。 然後我們再發版時,只能基於之前打好的war包,替換或者增加c

JVM成長之路,記錄記憶體溢位導致頻繁FGC的問題排查及解決

  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC  0.00  18.29  97.31  50.26  97.42  95.25