最近線上運行的hbase發現分配了16g內存,但是實際使用了22g,堆外內存達到6g。感覺非常詭異。堆外內存用一般的工具很難查看,可以通過google-perftools來跟蹤:
http://code.google.com/p/google-perftools/downloads/list
它的原理是在java應用程序運行時,當調用malloc時換用它的libtcmalloc.so,這樣就能做一些統計了
- 下載http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99-beta.tar.gz,configure;make;sudo make install
- 下載http://google-perftools.googlecode.com/files/google-perftools-1.8.1.tar.gz, configure --prefix=/home/user/perftools;make;sudo make install
- 在應用程序啟動前加入: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/pprof --text $JAVA_HOME/bin/java test_pid.xxxx.heap來查看
通過perftools查看到以下內容:
- Total: 3263.2 MB
- 3145.2 96.4% 96.4% 3145.2 96.4% zcalloc
- 83.8 2.6% 99.0% 83.8 2.6% os::malloc
- 30.0 0.9% 99.9% 30.0 0.9% init
- 2.2 0.1% 99.9% 2.2 0.1% ObjectSynchronizer::omAlloc
- 1.0 0.0% 100.0% 3144.1 96.4% Java_java_util_zip_Deflater_init
- 0.6 0.0% 100.0% 0.7 0.0% readCEN
可見調用了java.util.zip.Deflater占用絕大多數。了解到這個deflater存在無法釋放內存的bug,於是編寫btrace查看是否進入了這個函數:
- import static com.sun.btrace.BTraceUtils.*;
- import com.sun.btrace.annotations.*;
- import java.nio.ByteBuffer;
- import java.lang.Thread;
- @BTrace public class TestRegion1{
- @OnMethod(
- clazz="java.util.zip.Deflater",
- method="deflate"
- )
- public static void traceCacheBlock(){
- println("deflate?");
- }
- }
發現果然在不停調用這行代碼。應該如何辦呢?
由於deflater是gzip需要使用的代碼,查看用戶創建的表,發現COMPRESSOR設置的是GZ,嘗試調整為LZO,結果發現btrace無法進入上述代碼,再通過perftools查看時,堆內存不再申請,完全不再申請...
小插曲,perftools的作者是個老實人,提供了zip版下載,但是不提供安裝文件,原因?在README中有以下一段話:
- I don't know very much about how to install DLLs on Windows, so you'll
- have to figure out that part for yourself.

