google-perftools 分析JAVA 堆外記憶體
阿新 • • 發佈:2019-01-01
原文轉自:http://koven2049.iteye.com/blog/1142768,所有權利歸原作者所有
最近線上執行的hbase發現分配了16g記憶體,但是實際使用了22g,堆外記憶體達到6g。感覺非常詭異。堆外記憶體用一般的工具很難檢視,可以通過google-perftools來跟蹤:
- 在應用程式啟動前加入:export LD_PRELOAD=/home/hadoop/perftools/lib/libtcmalloc.so以及export HEAPPROFILE=/home/user/perftools/test
- 修改lc_config:sudo vi /etc/ld.so.conf.d/usr_local_lib.conf,加入/usr/local/lib(libunwind的lib所在目錄)
- 執行sudo /sbin/ldconfig,使libunwind生效
- 啟動應用程式,此時會在/home/user/perftools/下看到諸如test_pid.xxxx.heap的heap檔案,可使用bin/bin/pprof --text $JAVA_HOME/bin/java test_pid.xxxx.heap來檢視
通過perftools檢視到以下內容:
Java程式碼
- Total: 3263.2 MB
- 3145.296.4% 96.4% 3145.296.4% zcalloc
- 83.82.6% 99.0% 83.82.6% os::malloc
- 30.00.9
- 2.20.1% 99.9% 2.20.1% ObjectSynchronizer::omAlloc
- 1.00.0% 100.0% 3144.196.4% Java_java_util_zip_Deflater_init
- 0.60.0% 100.0% 0.70.0% readCEN
可見呼叫了java.util.zip.Deflater佔用絕大多數。瞭解到這個deflater存在無法釋放記憶體的bug,於是編寫btrace檢視是否進入了這個函式:
Java程式碼
- importstatic com.sun.btrace.BTraceUtils.*;
- import com.sun.btrace.annotations.*;
- import java.nio.ByteBuffer;
- import java.lang.Thread;
- @BTracepublicclass TestRegion1{
- @OnMethod(
- clazz="java.util.zip.Deflater",
- method="deflate"
- )
- publicstaticvoid traceCacheBlock(){
- println("deflate?");
- }
- }
發現果然在不停呼叫這行程式碼。應該如何辦呢?
由於deflater是gzip需要使用的程式碼,檢視使用者建立的表,發現COMPRESSOR設定的是GZ,嘗試調整為LZO,結果發現btrace無法進入上述程式碼,再通過perftools檢視時,堆記憶體不再申請,完全不再申請...
小插曲,perftools的作者是個老實人,提供了zip版下載,但是不提供安裝檔案,原因?在README中有以下一段話:
Html程式碼
- I don't know very much about how to install DLLs on Windows, so you'll
- have to figure out that part for yourself.