天道不一定酬所有勤
但是,天道只酬勤

天津11选5开奖结果走势图:class卸載、熱替換和Tomcat的熱部署的分析

開發十年,就只剩下這套架構體系了??!

一 class的熱替換

天津11选5蛋托玩法 www.ijudhr.com.cn ClassLoader中重要的方法

loadClass
ClassLoader.loadClass(...) 是ClassLoader的入口點。當一個類沒有指明用什么加載器加載的時候,JVM默認采用AppClassLoader加載器加載沒有加載過的class,調用的方法的入口就是loadClass(…)。如果一個class被自定義的ClassLoader加載,那么JVM也會調用這個自定義的ClassLoader.loadClass(…)方法來加載class內部引用的一些別的class文件。重載這個方法,能實現自定義加載class的方式,拋棄雙親委托機制,但是即使不采用雙親委托機制,比如java.lang包中的相關類還是不能自定義一個同名的類來代替,主要因為JVM解析、驗證class的時候,會進行相關判斷。

defineClass
系統自帶的ClassLoader,默認加載程序的是AppClassLoader,ClassLoader加載一個class,最終調用的是defineClass(…)方法,這時候就在想是否可以重復調用defineClass(…)方法加載同一個類(或者修改過),最后發現調用多次的話會有相關錯誤:

java.lang.LinkageError 
attempted duplicate class definition

所以一個class被一個ClassLoader實例加載過的話,就不能再被這個ClassLoader實例再次加載(這里的加載指的是,調用了defileClass(…)放方法,重新加載字節碼、解析、驗證。)。而系統默認的AppClassLoader加載器,他們內部會緩存加載過的class,重新加載的話,就直接取緩存。所與對于熱加載的話,只能重新創建一個ClassLoader,然后再去加載已經被加載過的class文件。

二 class卸載

在Java中class也是可以unload。JVM中class和Meta信息存放在PermGen space區域。如果加載的class文件很多,那么可能導致PermGen space區域空間溢出。引起:java.lang.OutOfMemoryErrorPermGen space. 對于有些Class我們可能只需要使用一次,就不再需要了,也可能我們修改了class文件,我們需要重新加載 newclass,那么oldclass就不再需要了。那么JVM怎么樣才能卸載Class呢。

JVM中的Class只有滿足以下三個條件,才能被GC回收,也就是該Class被卸載(unload):

  • 該類所有的實例都已經被GC。
  • 加載該類的ClassLoader實例已經被GC。
  • 該類的java.lang.Class對象沒有在任何地方被引用。

GC的時機我們是不可控的,那么同樣的我們對于Class的卸載也是不可控的。

1、有啟動類加載器加載的類型在整個運行期間是不可能被卸載的(jvm和jls規范).
2、被系統類加載器和標準擴展類加載器加載的類型在運行期間不太可能被卸載,因為系統類加載器實例或者標準擴展類的實例基本上在整個運行期間總能直接或者間接的訪問的到,其達到unreachable的可能性極小.(當然,在虛擬機快退出的時候可以,因為不管ClassLoader實例或者Class(java.lang.Class)實例也都是在堆中存在,同樣遵循垃圾收集的規則).
3、被開發者自定義的類加載器實例加載的類型只有在很簡單的上下文環境中才能被卸載,而且一般還要借助于強制調用虛擬機的垃圾收集功能才可以做到.可以預想,稍微復雜點的應用場景中(尤其很多時候,用戶在開發自定義類加載器實例的時候采用緩存的策略以提高系統性能),被加載的類型在運行期間也是幾乎不太可能被卸載的(至少卸載的時間是不確定的).

綜合以上三點, 一個已經加載的類型被卸載的幾率很小至少被卸載的時間是不確定的.同時,我們可以看的出來,開發者在開發代碼時候,不應該對虛擬機的類型卸載做任何假設的前提下來實現系統中的特定功能.

三 Tomcat中關于類的加載與卸載

Tomcat中與其說有熱加載,還不如說是熱部署來的準確些。因為對于一個應用,其中class文件被修改過,那么Tomcat會先卸載這個應用(Context),然后重新加載這個應用,其中關鍵就在于自定義ClassLoader的應用。這里有篇文章很好的介紹了tomcat中對于ClassLoader的應用。

Tomcat啟動的時候,ClassLoader加載的流程:

1 Tomcat啟動的時候,用system classloader即AppClassLoader加載{catalina.home}/bin里面的jar包,也就是tomcat啟動相關的jar包。 2 Tomcat啟動類Bootstrap中有3個classloader屬性,catalinaLoader、commonLoader、sharedLoader在Tomcat7中默認他們初始化都為同一個StandardClassLoader實例。具體的也可以在{catalina.home}/bin/bootstrap.jar包中的catalina.properites中進行配置。 3 StandardClassLoader加載{catalina.home}/lib下面的所有Tomcat用到的jar包。 4 一個Context容器,代表了一個app應用。Context–>WebappLoader–>WebClassLoader。并且Thread.contextClassLoader=WebClassLoader。應用程序中的jsp文件、class類、lib/*.jar包,都是WebClassLoader加載的。

當Jsp文件修改的時候,Tomcat更新步驟:

1 但訪問1.jsp的時候,1.jsp的包裝類JspServletWrapper會去比較1.jsp文件最新修改時間和上次的修改時間,以此判斷1.jsp是否修改過。 2 1.jsp修改過的話,那么jspservletWrapper會清除相關引用,包括1.jsp編譯后的servlet實例和加載這個servlet的JasperLoader實例。 3 重新創建一個JasperLoader實例,重新加載修改過后的1.jsp,重新生成一個Servlet實例。 4 返回修改后的1.jsp內容給用戶。

當app下面的class文件修改的時候,Tomcat更新步驟:

1 Context容器會有專門線程監控app下面的類的修改情況。 2 如果發現有類被修改了。那么調用Context.reload()。清楚一系列相關的引用和資源。 3 然后創新創建一個WebClassLoader實例,重新加載app下面需要的class。

在一個有一定規模的應用中,如果文件修改多次,重啟多次的話,java.lang.OutOfMemoryErrorPermGen space這個錯誤的的出現非常頻繁。主要就是因為每次重啟重新加載大量的class,超過了PermGen space設置的大小。兩種情況可能導致PermGen space溢出。 一、GC(Garbage Collection)在主程序運行期對PermGen space沒有進行清理(GC的不可控行), 二、重啟之前WebClassLoader加載的class在別的地方還存在著引用。

原文地址://www.blogjava.net/heavensay/archive/2012/11/07/389685.html

(全文完) 歡迎關注『Java之道』微信公眾號
贊(5)
如未加特殊說明,此網站文章均為原創,轉載必須注明出處。天津11选5蛋托玩法 » class卸載、熱替換和Tomcat的熱部署的分析
分享到: 更多 (0)

評論 搶沙發

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址

HollisChuang's Blog

聯系我關于我