最近,我留意到我的電腦在開機幾天後就會遭遇記憶體不足的問題。如下圖,透過Process Explorer,我發現Windows的Nonpaged核心記憶體(kernel-mode memory)部份有異常使用的現象,這個部份在剛開機的時候大約僅佔用100MB左右,正常狀況下不會有太明顯的變動,但是最近卻會隨時間慢慢增加,有時候可以增加到3GB以上(下圖的情況是增加到1GB),導致剩餘可給一般程式使用的記憶體(user-mode memory)變得不足。而這個現象讓我猜測是有常駐在核心的硬體驅動程式有臭蟲,導致有記憶體洩漏(memory leak)的現象。

為了證實這個想法並找出洩漏源頭,我使用這篇教學中的方法:http://goo.gl/qSKdYv,使用poolmon和Windows Performance Analyzer兩隻程式來進行分析。首先如下圖,poolmon的輸出顯示大部分的Nonpaged核心記憶體是由一類使用標籤為”Io”的程式所佔用的(下圖的例子中大約佔用832MB),而且這一類的記憶體的佔用量隨時間不斷上升,每次poolmon更新輸出都會增加32KB左右(下圖的例子中為31808bytes)。

接下來我們就要使用Windows Performance Recorder(WPR)和Windows Performance Analyzer(WPA)來找出究竟是哪一隻程式使用”Io”為標籤獲取記憶體,但是卻沒有正常歸還,導致產生記憶體洩漏的問題。我先以WPR紀錄了大約20分鐘核心記憶體的存取狀況,然後以WPA來顯示及分析這個紀錄檔。如下圖,我們可以在WPA中看到許多種在這20分鐘內以”Io”為標籤獲取核心記憶體,但卻沒有在這20分鐘內歸還(所謂的AIFO類別,Allocation Inside Free Outside)的call stack,驚人的是,這每一種call stack到最後都與csrbthav.sys有關(圖中我只展開了次數最多的call stack,50124次,獲取了6415872bytes)。整體而言,這1258秒內,csrbthav.sys大約向核心要了62212次沒有歸還的記憶體,每次要128bytes,導致大約洩漏了7961520bytes。

經查,如下圖,兇手csrbthav.sys屬於CSR的Harmony Bluetooth Software Stack,負責的是藍芽立體音訊的傳輸。而之所以安裝這套驅動程式,是因為我前陣子希望能透過藍芽無線傳輸高音質音訊到喇叭,買了一隻支援aptX的USB藍芽收發器Logitec LBT-UAN04C2BK。由於LBT-UAN04C2BK使用的是CSR8510 A10晶片,自然提供的就是CSR自家的Harmony藍芽驅動程式。

為了再次確認,我到控制台裡斷開與藍芽喇叭的無線連結,poolmon立刻顯示”Io”類別的記憶體佔用量停止增加,如下圖;如果重新連結到藍芽喇叭並播放音樂,無論喇叭是否支援aptX,”Io”類別的記憶體佔用量立刻恢復增加,即使停止播放音樂也一樣。至此,已經可以完全確定記憶體洩漏的兇手。以這樣的洩漏速度,每天大約會減少0.5GB的可以記憶體,而且由於洩漏的位置是在核心,不像一般程式一樣可以關掉重開就可以恢復正常,唯有重新開機一途。

悲劇的是,我目前安裝的Harmony驅動程式2.1.63.0版已經是最新版本,而且看來CSR從2012年之後就沒有再進行更新過。雖然市面上有其他廠商開發的一般性藍芽驅動程式也可以裝在這隻收發器上,但因為aptX是CSR的獨家技術,目前似乎沒有授權給其他軟體開發商,所以如果裝了就會喪失aptX的功能,就失去我當初買這個東西的意義了(如果要一般音質的藍芽模組,我電腦上本來就有了)。而且市面上幾乎所有支援aptX的USB藍芽收發器都是使用CSR的晶片,因此也沒有其他產品選擇。
為了確認不只是我電腦有問題,我在另一台安裝XP的電腦上進行測試(我原本的電腦是Win 7 x64),也有同樣的問題,但洩漏的速度有稍微緩慢一點。所以看來很可能各版本的Windows裝了Harmony都有一樣的問題。也歡迎已經購買相關產品並安裝了Harmony的網友自己進行測試。