乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      編程中國-Java 理論與實踐: 用弱引用堵住內(nèi)存泄漏

       chenge 2007-07-19
      C語言
      VB
      C++
      VC++
      JAVA
      Delphi
      匯編
      數(shù)據(jù)結(jié)構(gòu)
      軟件工程
      C技術(shù)資料
      C語言教程
      基礎(chǔ)教程
      編程技巧
      控件集錦
      編程實例
      優(yōu)化技術(shù)
      C++教程
      C++技術(shù)資料
      VC教程
      VC技術(shù)資料
      JAVA教程
      JAVA技術(shù)資料
      Delphi教程
      Delphi技術(shù)資料
      匯編教程
      匯編技術(shù)資料
      匯編源碼
      ASP
      JSP
      PHP
      JavaScript
      XML
      ASP教程
      ASP技術(shù)資料
      JSP教程
      JSP技術(shù)資料
      php教程
      PHP技術(shù)資料
      JavaScript教程
      JavaScript技術(shù)資料
      XML教程
      XML技術(shù)資料
      ASP.NET
      C#
      VB.NET
      VC.NET
      J#.NET
      Jscript.NET
      ASP.NET教程
      ASP.NET技術(shù)資料
      C#教程
      C#技術(shù)資料
      VB.NET教程
      VB.NET技術(shù)資料
      VC.NET教程
      VC.NET技術(shù)資料
      ACCESS
      VFP
      SQL Server
      MySQL
      Oracle
      PowerBuilder
      ACCESS教程
      ACCESS技術(shù)資料
      VFP教程
      VFP技術(shù)資料
      SQL Server教程
      SQL Server技術(shù)資料
      MySQL教程
      MySQL技術(shù)資料
      PB教程
      PB技術(shù)資料
      Windows
      Linux
      Unix
      HTML
      FrontPage
      Dreamweaver
      HTML教程
      HTML技術(shù)資料
      FrontPage教程
      FrontPage技術(shù)資料


        雖然用 Java? 語言編寫的程序在理論上是不會出現(xiàn)“內(nèi)存泄漏”的,但是有時對象在不再作為程序的邏輯狀態(tài)的一部分之后仍然不被垃圾收集。本月,負責保障應(yīng)用程序健康的工程師 Brian Goetz 探討了無意識的對象保留的常見原因,并展示了如何用弱引用堵住泄漏。
        要讓垃圾收集(GC)回收程序不再使用的對象,對象的邏輯 生命周期(應(yīng)用程序使用它的時間)和對該對象擁有的引用的實際 生命周期必須是相同的。在大多數(shù)時候,好的軟件工程技術(shù)保證這是自動實現(xiàn)的,不用我們對對象生命周期問題花費過多心思。但是偶爾我們會創(chuàng)建一個引用,它在內(nèi)存中包含對象的時間比我們預(yù)期的要長得多,這種情況稱為無意識的對象保留(unintentional object retention)。

        全局 Map 造成的內(nèi)存泄漏

        無意識對象保留最常見的原因是使用 Map 將元數(shù)據(jù)與臨時對象(transient object)相關(guān)聯(lián)。假定一個對象具有中等生命周期,比分配它的那個方法調(diào)用的生命周期長,但是比應(yīng)用程序的生命周期短,如客戶機的套接字連接。需要將 一些元數(shù)據(jù)與這個套接字關(guān)聯(lián),如生成連接的用戶的標識。在創(chuàng)建 Socket 時是不知道這些信息的,并且不能將數(shù)據(jù)添加到 Socket 對象上,因為不能控制 Socket 類或者它的子類。這時,典型的方法就是在一個全局 Map 中存儲這些信息,如清單 1 中的 SocketManager 類所示:

        清單 1. 使用一個全局 Map 將元數(shù)據(jù)關(guān)聯(lián)到一個對象

      public class SocketManager {
          private Map<Socket,User> m = new HashMap<Socket,User>();
         
          public void setUser(Socket s, User u) {
              m.put(s, u);
          }
          public User getUser(Socket s) {
              return m.get(s);
          }
          public void removeUser(Socket s) {
              m.remove(s);
          }
      }

      SocketManager socketManager;
      ...
      socketManager.setUser(socket, user);

        這種方法的問題是元數(shù)據(jù)的生命周期需要與套接字的生命周期掛鉤,但是除非準確地知道什么時候程序不再需要這個套接字,并記住從 Map 中刪除相應(yīng)的映射,否則,Socket 和 User 對象將會永遠留在 Map 中,遠遠超過響應(yīng)了請求和關(guān)閉套接字的時間。這會阻止 Socket 和 User 對象被垃圾收集,即使應(yīng)用程序不會再使用它們。這些對象留下來不受控制,很容易造成程序在長時間運行后內(nèi)存爆滿。除了最簡單的情況,在幾乎所有情況下找出 什么時候 Socket 不再被程序使用是一件很煩人和容易出錯的任務(wù),需要人工對內(nèi)存進行管理。

        找出內(nèi)存泄漏

        程序有內(nèi)存泄漏的第一個跡象通常是它拋出一個 OutOfMemoryError,或者因為頻繁的垃圾收集而表現(xiàn)出糟糕的性能。幸運的是,垃圾收集可以提供能夠用來診斷內(nèi)存泄漏的大量信息。如果以 -verbose:gc 或者 -Xloggc 選項調(diào)用 JVM,那么每次 GC 運行時在控制臺上或者日志文件中會打印出一個診斷信息,包括它所花費的時間、當前堆使用情況以及恢復(fù)了多少內(nèi)存。記錄 GC 使用情況并不具有干擾性,因此如果需要分析內(nèi)存問題或者調(diào)優(yōu)垃圾收集器,在生產(chǎn)環(huán)境中默認啟用 GC 日志是值得的。

        有工具可以利用 GC 日志輸出并以圖形方式將它顯示出來,JTune 就是這樣的一種工具(請參閱 參考資料)。觀察 GC 之后堆大小的圖,可以看到程序內(nèi)存使用的趨勢。對于大多數(shù)程序來說,可以將內(nèi)存使用分為兩部分:baseline 使用和 current load 使用。對于服務(wù)器應(yīng)用程序,baseline 使用就是應(yīng)用程序在沒有任何負荷、但是已經(jīng)準備好接受請求時的內(nèi)存使用,current load 使用是在處理請求過程中使用的、但是在請求處理完成后會釋放的內(nèi)存。只要負荷大體上是恒定的,應(yīng)用程序通常會很快達到一個穩(wěn)定的內(nèi)存使用水平。如果在應(yīng)用 程序已經(jīng)完成了其初始化并且負荷沒有增加的情況下,內(nèi)存使用持續(xù)增加,那么程序就可能在處理前面的請求時保留了生成的對象。

        清單 2 展示了一個有內(nèi)存泄漏的程序。MapLeaker 在線程池中處理任務(wù),并在一個 Map 中記錄每一項任務(wù)的狀態(tài)。不幸的是,在任務(wù)完成后它不會刪除那一項,因此狀態(tài)項和任務(wù)對象(以及它們的內(nèi)部狀態(tài))會不斷地積累。

        清單 2. 具有基于 Map 的內(nèi)存泄漏的程序

      public class MapLeaker {
          public ExecutorService exec = Executors.newFixedThreadPool(5);
          public Map<Task, TaskStatus> taskStatus
              = Collections.synchronizedMap(new HashMap<Task, TaskStatus>());
          private Random random = new Random();

          private enum TaskStatus { NOT_STARTED, STARTED, FINISHED };

          private class Task implements Runnable {
              private int[] numbers = new int[random.nextInt(200)];

              public void run() {
                  int[] temp = new int[random.nextInt(10000)];
                  taskStatus.put(this, TaskStatus.STARTED);
                  doSomeWork();
                  taskStatus.put(this, TaskStatus.FINISHED);
              }
          }

          public Task newTask() {
              Task t = new Task();
              taskStatus.put(t, TaskStatus.NOT_STARTED);
              exec.execute(t);
              return t;
          }
      }

        圖 1 顯示 MapLeaker GC 之后應(yīng)用程序堆大小隨著時間的變化圖。上升趨勢是存在內(nèi)存泄漏的警示信號。(在真實的應(yīng)用程序中,坡度不會這么大,但是在收集了足夠長時間的 GC 數(shù)據(jù)后,上升趨勢通常會表現(xiàn)得很明顯。)


      圖 1. 持續(xù)上升的內(nèi)存使用趨勢

        確信有了內(nèi)存泄漏后,下一步就是找出哪種對象造成了這個問題。所有內(nèi)存分析器都可以生成按照對象類進行分解的堆快照。有一些很好的商業(yè)堆分析工 具,但是找出內(nèi)存泄漏不一定要花錢買這些工具 —— 內(nèi)置的 hprof 工具也可完成這項工作。要使用 hprof 并讓它跟蹤內(nèi)存使用,需要以 -Xrunhprof:heap=sites 選項調(diào)用 JVM。

        清單 3 顯示分解了應(yīng)用程序內(nèi)存使用的 hprof 輸出的相關(guān)部分。(hprof 工具在應(yīng)用程序退出時,或者用 kill -3 或在 Windows 中按 Ctrl+Break 時生成使用分解。)注意兩次快照相比,Map.Entry、Task 和 int[] 對象有了顯著增加。

        請參閱 清單 3。

        清單 4 展示了 hprof 輸出的另一部分,給出了 Map.Entry 對象的分配點的調(diào)用堆棧信息。這個輸出告訴我們哪些調(diào)用鏈生成了 Map.Entry 對象,并帶有一些程序分析,找出內(nèi)存泄漏來源一般來說是相當容易的。

        清單 4. HPROF 輸出,顯示 Map.Entry 對象的分配點

      TRACE 300446:
       Java.util.HashMap$Entry.<init>(<Unknown Source>:Unknown line)
       Java.util.HashMap.addEntry(<Unknown Source>:Unknown line)
       Java.util.HashMap.put(<Unknown Source>:Unknown line)
       Java.util.Collections$SynchronizedMap.put(<Unknown Source>:Unknown line)
       com.quiotix.dummy.MapLeaker.newTask(MapLeaker.Java:48)
       com.quiotix.dummy.MapLeaker.main(MapLeaker.Java:64)

       

       

       

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多