1. 程式人生 > >從tomcat的永久區溢出看類加載方式以及內存分析工具

從tomcat的永久區溢出看類加載方式以及內存分析工具

pan nan ade itl lvm tails except pro ava

tomcat熱部署導致的溢出:

tomcat設置為熱部署狀態 reload=‘true’可能會產生永久區的內存溢出,首先永久區存儲的是類的class信息,日誌報出的信息有CGLIB的報錯信息,查了一下有說CGLIB的動態代理占用了大量的永久區,所以再加上tomcat reload時候舊的類信息沒有辦法gc就導致了永久區內存溢出。

加載方式和熱部署原理

java加載方式:

java加載的方式是通過classloader對象加載,自帶的classloader有sun.misc.Launcher$AppClassLoader,Bootstrap,bootstrap是由c/c++寫的,在虛擬機運行時加載類,AppclassLoader是常用的classloader,通過ClassLoader.getSystemClassLoader方法獲得的就是appclassloader對象,除此外還有URLClassLoader,欽定的這些classloader有一個特點叫雙親加載機制:
  1. protected
    Class<?> loadClass(String name, boolean resolve)
  2. throws ClassNotFoundException
  3. {
  4. synchronized (getClassLoadingLock(name)) {
  5. // First, check if the class has already been loaded
  6. Class<?> c = findLoadedClass(name);
  7. if (c == null) {
  8. long t0 = System.nanoTime();
  9. try {
  10. if (parent != null) {
  11. c = parent.loadClass(name, false);
  12. } else {
  13. c = findBootstrapClassOrNull(name);
  14. }
  15. } catch (ClassNotFoundException
    e) {
  16. // ClassNotFoundException thrown if class not found
  17. // from the non-null parent class loader
  18. }
  19. if (c == null) {
  20. // If still not found, then invoke findClass in order
  21. // to find the class.
  22. long t1 = System.nanoTime();
  23. c = findClass(name);
  24. // this is the defining class loader; record the stats
  25. sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
  26. sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
  27. sun.misc.PerfCounter.getFindClasses().increment();
  28. }
  29. }
  30. if (resolve) {
  31. resolveClass(c);
  32. }
  33. return c;
  34. }
  35. }
這個classloader的方法可以看出雙親委托機制:
  1. 1. 當前ClassLoader首先從自己已經加載的類中查詢是否此類已經加載,如果已經加載則直接返回原來已經加載的類。每個類加載器都有自己的加載緩存,當一個類被加載了以後就會放入緩存,等下次加載的時候就可以直接返回了。
  2. 2. 當前classLoader的緩存中沒有找到被加載的類的時候,委托父類加載器去加載,父類加載器采用同樣的策略,首先查看自己的緩存,然後委托父類的父類去加載,一直到bootstrp ClassLoader.
  3. 3. 當所有的父類加載器都沒有加載的時候,再由當前的類加載器加載,並將其放入它自己的緩存中,以便下次有加載請求的時候直接返回。
所以如果想實現熱加載,就要擺脫雙親委托的機制,可以看到load方法並不是final所以是可以自定義的,還有一點需要註意的是類的命名空間是由全類名加類加載器所構成的,也就是說類加載器不同所加載出來的類就會欽定為不同,所以可能出現
  1. com.wks.TestReloadClass.Hot cannot be cast to com.wks.TestReloadClass.Hot
的錯誤,還有要實現熱加載,classloader每次都要new一個新的,不然一次之後就不能再加載同一個類了,對於已經加載了得類信息,由於jvmgc的不確定性,很不容易被gc掉,必須要所有引用都null,包括所對應的classloader,這也是tomcat永久區溢出的原因

熱加載的實現:

  1. -verbose:class //vm參數,看class的加載和卸載信息
代碼見附件

內存分析工具jvisualvm

jdk自帶的內存分析工具,在jre/bin目錄下,可以監控正在運行的java程序,查看cpu 內存,類,對象,也可以查看dmp文件,通過監控tomcat的reload,看到了多個同一類的類信息:

參考

http://blog.csdn.net/wangyang1354/article/details/49448007 http://www.blogjava.net/heavensay/archive/2012/11/07/389685.html


null

附件列表

    從tomcat的永久區溢出看類加載方式以及內存分析工具