Axis2 webservice close_wait,java heap space錯誤的研究

 
Axis2 webservice close_wait,java heap space錯誤的研究
2009-05-20 16:20
客戶端僞代碼如下
//主線程方法
while(true){
            test.TestGetServiceStatus();//客戶端連接服務端的測試方法
            try{
                Thread.sleep(23 * 1000);//每隔23秒執行下webservice客戶端方法
            }catch(Exception e){
                e.printStackTrace();
            }
}

private String wsUrl = "http://127.0.0.1:8080/axis2/services/webservice/";
    public void TestGetServiceStatus(){
        WebserviceStub stub = null;
        try{
            stub = new WebserviceStub(wsUrl);//實例華客戶端
            System.out.println("new a stub");
            Thread.sleep(5000);//5秒鐘後執行客戶端向服務端的請求

            String result = stub.queryServiceStatus(request).getResult();//請求服務端
            System.out.println("result: " + result);
//清除客戶端
            stub._getServiceClient().cleanupTransport();
            stub._getServiceClient().cleanup();
            stub.cleanup();
            stub = null;
        }catch(Exception e){
}
    }
步驟解釋:
1、主線程每隔23秒調用方法,來實現客戶端對服務端的調用
2、客戶端在對服務段進行藉口調用時:
    2.1、實例化客戶端對象
    2.2、睡5秒鐘
    2.3、調用服務端接口,得到結果
     2.4、清除客戶端
3、服務端的相應接口,收到請求後,睡眠25秒,給出結果。
4、webservice服務端配置文件裏,加入連接的存活時間,爲20s,如下(axis2.xml):
<transportReceiver name="http"
         class="org.apache.axis2.transport.http.SimpleHTTPServer">
        <parameter name="port">8080</parameter>
    <parameter name="threadKeepAliveTime">20</parameter>
</transportReceiver>
基於以上的調用,用ethereal抓包得到下圖:
(圖片看不清楚,可以點擊圖片進行查看

注意兩個綠色框的內容,詳細過程分析如下:
1、new stub的時候,客戶端與服務端並沒有連接;
2、5秒鐘後,客戶端向服務端發送請求,連接建立,如圖的1—7個數據包;
3、測試客戶端做出處理,即睡眠25秒,之後返回數據,如圖的8—23個數據包;
4、客戶端收到數據後,cleanup,方法退出,但是此時看到連接並沒有關閉;
5、服務端在20秒後(設置的連接存活時間),斷開連接,如圖的24,25個數據包;
6、由於客戶端這邊在25秒的時候(23個數據包所示)退出了方法,過23秒後重新調用測試方法,於是應該在48秒的時候,重新new stub,這個時候,看圖知道,在第26個數據包的時候(也就是48秒的時候)客戶端發出了先前連接的斷開包,至此前一個連接完全釋放,開始下一輪的連接循環。
由此可以得出:
1、客戶端new stub的時候,並沒有與服務端建立連接,而只是釋放之前的連接;
2、連接是由服務端先發起的;
3、客戶端發送服務端請求的時候,連接由客戶端發起,並建立;
由上面的結論可以分析出一個問題:客戶端在調用服務端接口方法,並退出後,連接還存在,直到連接存活時間達到服務端設置的連接存活時間後,才被服務端所關閉,這個時候,如果客戶端不再重新發起請求,或者客戶端出錯(內存溢出,無法new stub等),那麼之前的那個連接就一直會處在close_wait狀態,而無法清除。這就是爲什麼有些webservice客戶端這邊,跑了一段時間後,會出現很多close_wait狀態的連接的緣故。
    再來看,是什麼原因導致了new stub的時候出錯的呢?上面也講到了,雖然可能性有很多,但是有一個卻是大家經常犯的,那就是客戶端這邊內存溢出了。
    很多webservice客戶端,在跑了很長時間後,發現內存就不夠用了,拋出java heap space的錯誤,隨之而來的就是類似Read Timeout阿等錯誤,這樣close_wait就越來越多,這些錯誤也會越拋越多……直到整個客戶端都無法與服務端取得任何連接,而進入“假死”狀態。那麼如何避免客戶端內存持續走高呢?
    通過jdk自帶的jconsole和eclipse提供的memory analyzer可以看到,客戶端這邊的內存在不斷上升,java的gc根本無法釋放使用過的內存,而通過memory analyzer可以看到,很多堆內存都在客戶端調用服務端的方法裏,無法釋放(圖就不上了)。也就是說,這不是我們實現某功能時自己的原因導致的內存溢出,而是axis2本身的內存溢出。那是不是就沒有辦法解決了呢?不是的!
    細心的你有沒有注意到開篇的時候我提供的客戶端的僞代碼?裏面有四句:
stub._getServiceClient().cleanupTransport();
        stub._getServiceClient().cleanup();
        stub.cleanup();
        stub = null;
當時加這四句代碼,只是爲了驗證客戶端時候能把連接主動關閉,可是結果是否定的,但是,恰好是這幾句解決了內存溢出的問題!只要在每次客戶端調用後,都執行以上四句代碼,那麼客戶端new出來的堆內存資源就可以被java的gc所回收掉了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章