ALL is Well!

          敏捷是一條很長的路,摸索著前進著

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            30 隨筆 :: 23 文章 :: 71 評論 :: 0 Trackbacks

          最近一段時間,在公司里對java內存泄露的問題進行了調查。

          問題的發現:

          系統中在連續不停地、反復進行一個操作(先打開A,然后切替到畫面B,點擊畫面履歷再回到A,如此反復)。經過長時間的測試,經常會20小時,JVM的內存使用量增長30M以上。

           

          問題的分析:

          首先根據操作,找到會執行的代碼,對代碼進行分析。

          Java會產生內存泄露的原因,經過本次調查,

          1.對于打開的socket等資源,沒有做及時的回收處理。
          2.生存周期較長的對象,持有了生存周期較短的對象的引用,以至于那些生存周期短的對象,在無用的情況下,沒有得到回收。
          3.對于類的成員變量為集合的情況,對集合的使用應該謹慎。比如,一個專門保存用戶操作履歷的對象,有全局變量List來保存用戶所有點擊過的鏈接。但實際項目中,不可能保存住用戶的每一次鏈接操作,然后顯示給用戶,有時候可能只是顯示最新的20條。所以這時候就要對這個全局變量進行處理,不能讓它無限的膨脹下去。
          4.在類的成員變量為集合的情況,集合中的元素又是比較復雜的對象,(這個對象中可能還包含著是集合的成員變量)在不需要此類的對象的時候,應該自己來實現對類的成員的銷毀。如:
          1Iterator itor = myMap.keySet().iterator();   
          2while (itor.hasNext()) {   
          3    MyObject selectedInfo = (MyObject) itor.next();   
          4    selectedInfo.destroy();// 假設MyObject里有destroy方法,對MyObjec中的成員進行銷毀   
          5    selectedInfo = null;   
          6}
             
          7myMap.clear();  

          5.對單態模式應該慎用,象在被初始化后將在JVM的整個生命周期中存在如果單態象持有外部象的引用,那么這個外部象將不能被回收,如故這個外部對象很龐大,那么對內存的消耗是很大的。
          6.雖然寫java程序,有GC幫助我們管理內存,但好的編程習慣還是需要的,可以避免不必要的麻煩。

          雖然寫java程序,有GC幫助我們管理內存,但好的編程習慣還是需要的,可以避免不必要的麻煩。

          1.復雜的對象,在不需要的情況下,最好能實現對它的成員的銷毀,然后再將其賦為null
          2.對于打開的流,一定要做及時的處理。另外對于HttpURLConnection對象,連接后,要調用它的disconnect(),不要對資源進行不必要的浪費。
          3.盡量少用全局變量。
          4.在哪里生成對象,就在哪里銷毀它。
          5.盡量避免對象之間的相互引用。

          最后,記述一下我記錄內存的方法。

          由于對代碼做好修改之后,要確認一下內存是否有明顯增長。

          于是寫一段代碼,每個5分鐘對對內存進行一次記錄,在連續運行20小時候,做成曲線圖,以便分析。

          (以下是為了方便,重新寫的,原來項目中用到的,有一整套完備的定時器生成和起動的管理類,這里沒有寫出來。)

           1import java.io.DataOutputStream;   
           2import java.io.FileOutputStream;   
           3import java.io.IOException;   
           4public class MemoryCollect {   
           5    public static void main(String args[]) {   
           6        MemoryCollector mc = new MemoryCollector(300000);   
           7        mc.start();   
           8    }
             
           9}
             
          10class MemoryCollector extends java.util.TimerTask {   
          11    private static final java.text.NumberFormat nf = java.text.NumberFormat   
          12            .getPercentInstance();   
          13    private static final java.text.DateFormat df = new java.text.SimpleDateFormat(   
          14            "yyyy-MM-dd HH:mm:ss");   
          15    private DataOutputStream dos = null;   
          16    private long period = 0;   
          17    private java.util.Timer timer = null;   
          18    MemoryCollector(long p) {   
          19        period = p;   
          20        timer = new java.util.Timer();   
          21    }
             
          22    public void start() {   
          23        timer.schedule(this0, period);   
          24    }
             
          25    public void run() {   
          26        System.gc();   
          27        Runtime imp = Runtime.getRuntime();   
          28        imp.totalMemory();   
          29        long totol = imp.totalMemory() / 1024;   
          30        long free = imp.freeMemory() / 1024;   
          31        try {   
          32            dos = new DataOutputStream(new FileOutputStream("D:\\memory.txt",   
          33                    true));   
          34            String date = df.format(new java.util.Date());   
          35            String info = date + "\t" + totol + "\t" + free + "\t"  
          36                    + nf.format((double) free / (double) totol);   
          37            System.out.println(info);   
          38            dos.writeUTF(info + "\r");   
          39            dos.flush();   
          40            dos.close();   
          41            dos = null;   
          42        }
           catch (Exception e) {   
          43            System.out.println(e);   
          44        }
           finally {   
          45            try {   
          46                if (dos != null{   
          47                    dos.flush();   
          48                    dos.close();   
          49                    dos = null;   
          50                }
             
          51            }
           catch (IOException e) {   
          52                e.printStackTrace();   
          53            }
             
          54        }
             
          55    }
             
          56    public void stop() {   
          57        super.cancel();   
          58        if (timer != null{   
          59            timer.cancel();   
          60            timer = null;   
          61        }
             
          62    }
             
          63}
           


          ----2009年02月02日
          posted on 2010-09-01 11:31 李 明 閱讀(1057) 評論(0)  編輯  收藏 所屬分類: 技術知識
          主站蜘蛛池模板: 莲花县| 体育| 井研县| 蒲江县| 漳州市| 庆云县| 佛山市| 凤山县| 遂平县| 江源县| 庄河市| 拉孜县| 怀集县| 黄冈市| 武川县| 琼海市| 宝坻区| 噶尔县| 曲阜市| 尼勒克县| 昌邑市| 沙湾县| 民权县| 泽库县| 罗山县| 金昌市| 翁牛特旗| 株洲县| 舞钢市| 凤凰县| 米林县| 吉首市| 江永县| 文登市| 庆元县| 巴彦淖尔市| 永善县| 吉木乃县| 崇礼县| 彝良县| 扬中市|