1. 程式人生 > >perftools檢視JVM堆外記憶體

perftools檢視JVM堆外記憶體

最近線上執行的hbase發現分配了16g記憶體,但是實際使用了22g,堆外記憶體達到6g。感覺非常詭異。堆外記憶體用一般的工具很難檢視,可以通過google-perftools來跟蹤: 
http://code.google.com/p/google-perftools/downloads/list 
    它的原理是在java應用程式執行時,當呼叫malloc時換用它的libtcmalloc.so,這樣就能做一些統計了 

  • 在應用程式啟動前加入: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程式碼  收藏程式碼
  1. Total: 3263.2 MB  
  2.   3145.2
    96.4%  96.4%   3145.296.4% zcalloc  
  3.     83.82.6%  99.0%     83.82.6% os::malloc  
  4.     30.00.9%  99.9%     30.00.9% init  
  5.      2.20.1%  99.9%      2.20.1% ObjectSynchronizer::omAlloc  
  6.      1.00.0100.0%   3144.196.4% Java_java_util_zip_Deflater_init  
  7.      0.60.0100.0%      0.70.0% readCEN  

    可見呼叫了java.util.zip.Deflater佔用絕大多數。瞭解到這個deflater存在無法釋放記憶體的bug,於是編寫btrace檢視是否進入了這個函式: 
Java程式碼  
收藏程式碼
  1. importstatic com.sun.btrace.BTraceUtils.*;  
  2. import com.sun.btrace.annotations.*;  
  3. import java.nio.ByteBuffer;  
  4. import java.lang.Thread;  
  5. @BTracepublicclass TestRegion1{  
  6.    @OnMethod(  
  7.       clazz="java.util.zip.Deflater",  
  8.       method="deflate"
  9.    )  
  10.    publicstaticvoid traceCacheBlock(){  
  11. println("deflate?");  
  12.    }  
  13. }  

    發現果然在不停呼叫這行程式碼。應該如何辦呢? 
  由於deflater是gzip需要使用的程式碼,檢視使用者建立的表,發現COMPRESSOR設定的是GZ,嘗試調整為LZO,結果發現btrace無法進入上述程式碼,再通過perftools檢視時,堆記憶體不再申請,完全不再申請... 
  小插曲,perftools的作者是個老實人,提供了zip版下載,但是不提供安裝檔案,原因?在README中有以下一段話: 
   Html程式碼  收藏程式碼
  1. I don't know very much about how to install DLLs on Windows, so you'll  
  2. have to figure out that part for yourself.