簡介:調優的並不總是速度,有時候需要調整應用程式的其他方面,如果應用程式需要調優,要做的 第一件事通常是使用剖析程式監控應用程式。但是,剖析並不總是可行的,有時候原因可能很可笑。關注 效能的本期文章中, Jack 和 Kirk 講述了他們最近經曆的一件事:他們奉命剖析一個胖客戶機,事實上 它是如此龐大,根本沒有為剖析程式留下空間。
我們從來還沒有遇到過調優應用程式記憶體佔用的問題。通常,我們看到的和記憶體有關的調優要求都涉 及到降低垃圾收集的開銷,理想情況下可以通過調整堆的大小或者改變垃圾收集演算法來解決,如果不行的 話,還可以採用各種技術減少記憶體中的對象。但是,有時候無論分配和垃圾收集的效率如何,應用程式都 要佔用很多的記憶體。
減肥中心之旅
最近,我們奉命降低一個胖客戶機的記憶體佔用。雖然“胖客戶機”一詞通常表示普通的 GUI 客戶應用 程式,而這個客戶機卻是幾近肥胖症。這個客戶機在 Windows 平台上運行,處理大小的極限是 2 GB。去 掉可執行地址空間和引入各種 JNI 產品所需要的其他空間之後,該應用程式能夠使用的最大堆大小大約 是 1.2 GB 或者 1.3 GB。不幸的是,某些使用者因為要向該應用程式灌輸大量的資料,以至於佔用的空間 常常接近這個極限。最明顯的調優方案是轉移到 Unix 機器上,但是因為不切實際而被排除掉了——客戶 更願意讓這個應用程式減肥。
於是,我們的任務就定下來了。對這個胖客戶機進行剖析,看看到底是什麼佔用了這些空間。然後對 這些對象減肥,為以後的擴充或者更大的資料量留下空間。我們認為這事很容易。可能要花點時間,因為 減少對象的數量通常不能一蹴而就,但是這麼大的堆, 肯定有很多贅肉能夠割掉。我們這樣想。
通常的過程
我們開始了通常的記憶體佔用縮減過程:建立測試環境、規定可再現的測試、啟動剖析程式、運行測試 、分析資料、尋找調優的機會。時間不斷流逝,我們一直忙個不停……或者說我們是這樣認為的。現在, 我們進入了“運行測試”階段,剖析程式趴下了。於是我們再次嘗試。又死掉了。我們改變了剖析程式的 配置,將開銷減到最少,再次嘗試。又死掉了。根本就沒留下足夠容納剖析程式完全啟動並執行 JVM 堆空間 ,更不用說產生任何有用的剖析資料了。而我們使用的是一種上等的商業剖析程式,一般是很可靠的,所 以我們很吃驚。
試一次,再試一次
沒關係,海裡有數不清的魚,現在也有數不清的剖析程式(關於剖析程式的最新評述,請參閱 Resources)。又是一天,又使用了一個剖析程式,怎麼樣呢?不幸的是,測試過程是驚人的相似。和一 號剖析程式差不多在同一點上,二號剖析程式又讓 JVM 崩潰了。和一號剖析程式一樣,它甚至可以做更 多的配置,重新設定,降低開銷,去掉更多的資料。但它還是和一號剖析程式一樣,也崩潰了。糟糕的是 ,三號剖析程式也沒有什麼不同。
巧妙的剖析程式
但是,四號剖析程式有了微妙的變化。對存活對象的快照進行記憶體分析(忽略對象的建立和垃圾收集 ,只觀察某一點上存活對象的快照),在請求進行快照之前,四號剖析程式根本沒有增加 JVM 的開銷。 成功了!我們的測試第一次在剖析程式啟動並執行時候通過了需要拍攝快照的那個點。我們很高興。然後我們 啟用了快照,於是 JVM 崩潰了。
我們又嘗試了一次,但是這個剖析程式產生快照需要太多的額外空間。根本無法工作。我們又回到了 起點!儘管還有半打商業剖析程式可供嘗試,但結果是顯然的。應該做一些橫向思考了。
具有諷刺意味的是,我們的問題正在於剖析程式本身的複雜性。我們需要某種簡單的東西。當然,簡 單並不意味著開銷低,但是既然那些複雜的剖析程式令我們失望,不妨試一試。於是我們開始掃描開放源 代碼剖析程式。