1. 程式人生 > >java物件的初始化和回收

java物件的初始化和回收

物件的初始化和回收

        系統生成物件時,會自動為物件分配記憶體空間,並呼叫相應的建構函式對其初始化,在物件沒有任何引用繫結時,垃圾回收器會週期行掃描記憶體情況並進行回收。

  • 初始化

        物件的生成和初始化是一體的概念,生成了物件就會對其初始化。Java提供了四種方法生成物件,使用new關鍵字僅僅是其中一種方法。

        1. 使用new關鍵字生成物件。

        2. 使用反射機制動態生成物件。利用Class,ClassLoader和Constructor類的方法動態生成物件。詳情會在Java反射機制中解釋。

        3. 使用克隆生成物件。如果一個類實現了Cloneable介面,這個類的物件可以通過使用clone()方法生成該物件的一份拷貝。

        4. 使用反序列化從流中生成對物件。從磁碟中讀取相應的輸入流的讀取方法來生成新的物件。這個方法將在序列化中詳細解釋。

  • 回收

        垃圾回收是系統自動完成的。當一個物件不再使用,系統會將引用變數的值賦為null,同時呼叫物件的finalize()方法銷燬物件。

        finalize()是一個被保護的方法,可由子類對其複寫,需要注意的是,java機制並不保證該方法一定會被執行,如果向顯式呼叫,可以使用System.gc(),詳細資訊會在JVM中描述。


1. 垃圾回收
 

   垃圾回收是Java程式設計中記憶體管理的核心概念,JVM的記憶體管理機制被稱為垃圾回收機制。 

  一個物件建立後被放置在JVM的堆記憶體中,當永遠不再引用這個物件時,它將被JVM在堆記憶體中回收。被建立的物件不能再生,同時也沒有辦法通過程式語句釋放它們。即當物件在JVM執行空間中無法通過根集合到達(找到)時,這個物件被稱為垃圾物件。根集合是由類中的靜態引用域與本地引用域組成的。JVM通過根集合索引物件。 

    在做Java應用開發時經常會用到由JVM管理的兩種型別的記憶體:堆記憶體和棧記憶體。簡單來講,堆記憶體主要用來儲存程式在執行時建立或例項化的物件與變數。例如通過new關鍵字建立的物件。而棧記憶體則是用來儲存程式程式碼中宣告為靜態或非靜態的方法。

 

(1) 堆記憶體 

    堆記憶體在JVM啟動的時候被建立,堆記憶體中所儲存的物件可以被JVM自動回收,不能通過其他外部手段回收,也就是說開發人員無法通過新增相關程式碼的手段來回收堆記憶體中的物件。堆記憶體通常情況下被分為兩個區域:新物件區域與老物件區域。 

    新物件區域:又可細分為三個小區域:伊甸園區域、From區域與To區域。伊甸園區域用來儲存新建立的物件,它就像一個堆疊,新的物件被建立,就像指向該棧的指標在增長一樣,當伊甸園區域中的物件滿了之後,JVM系統將要做到可達性測試,主要任務是檢測有哪些物件由根集合出發是不可達的,這些物件就可以被JVM回收,並且將所有的活動物件從伊甸園區域拷貝到To區域,此時一些物件將發生狀態交換,有的物件就從To區域被轉移到From區域,此時From區域就有了物件。上面物件遷移的整個過程,都是由JVM控制完成的。 

    老物件區域:在老物件區域中的物件仍然會有一個較長的生命週期,大多數的JVM系統垃圾物件,都是源於"短命"物件,經過一段時間後,被轉入老物件區域的物件,就變成了垃圾物件。此時,它們都被打上相應的標記,JVM系統將會自動回收這些垃圾物件,建議不要頻繁地強制系統作垃圾回收,這是因為JVM會利用有限的系統資源,優先完成垃圾回收工作,導致應用無法快速地響應來自使用者端的請求,這樣會影響系統的整體效能。
 

(2) 棧記憶體 

    堆記憶體主要用來儲存程式在執行時建立或例項化的物件與變數。例如通過new關鍵字建立的物件。而棧記憶體則是用來儲存程式程式碼中宣告為靜態或非靜態的方法。 

2. JVM中物件的生命週期 

   在JVM執行空間中,物件的整個生命週期大致可以分為7個階段: 
   建立階段; 
   應用階段; 
   不可視階段; 
   不可到達階段; 
   可收集階段; 
   終結階段; 
   釋放階段
  

   上面這7個階段,構成了JVM中物件的完整的生命週期。 


   (1) 建立階段 

       在物件的建立階段,系統主要通過下面的步驟,完成物件的建立過程: 
     
       <1> 為物件分配儲存空間; 
       <2> 開始構造物件; 
       <3> 從超類到子類對static成員進行初始化; 
       <4> 超類成員變數按順序初始化,遞迴呼叫超類的構造方法; 
       <5> 子類成員變數按順序初始化,子類構造方法呼叫。 

       在建立物件時應注意幾個關鍵應用規則: 
       
       <1> 避免在迴圈體中建立物件,即使該物件佔用記憶體空間不大。 
       <2> 儘量及時使物件符合垃圾回收標準。比如 myObject = null。 
       <3> 不要採用過深的繼承層次。 
       <4> 訪問本地變數優於訪問類中的變數。

 (2) 應用階段 

       在物件的引用階段,物件具備如下特徵: 

      <1> 系統至少維護著物件的一個強引用(Strong Reference); 
      <2> 所有對該物件的引用全部是強引用(除非我們顯示地適用了:軟引用(Soft Reference)、弱引用(Weak Reference)或虛引用(Phantom Reference)).
 

      強引用(Strong Reference):是指JVM記憶體管理器從根引用集合出發遍歷堆中所有到達物件的路徑。當到達某物件的任意路徑都不含有引用物件時,這個物件的引用就被稱為強引用。 

       軟引用(Soft Reference):軟引用的主要特點是有較強的引用功能。只有當記憶體不夠的時候,才回收這類記憶體,因此記憶體足夠時它們通常不被回收。另外這些引用物件還能保證在Java丟擲OutOfMemory異常之前,被設定為null。它可以用於實現一些常用資源的快取,實現Cache功能,保證最大限度地使用記憶體你而不引起OutOfMemory。

下面是軟引用的實現程式碼: import java.lang.ref.SoftReference; ... A a = new A(); ... // 使用a ... // 使用完了a, 將它設定為soft引用型別,並且釋放強引用 SoftReference sr = new SoftReference(a); a = null; ... // 下次使用時 if (sr != null) { a = sr.get(); } else { // GC由於低記憶體,已釋放a,因此需要重新裝載 a = new A(); sr = new SoftReference(a); }

 軟引用技術的引進使Java應用可以更好地管理記憶體,穩定系統,防止系統記憶體溢位,避免系統崩潰。因此在處理一些佔用記憶體較大且生命週期較長,但使用並不繁地物件時應儘量應用該技術。提高系統穩定性。 
             
                                      
       弱引用(Weak Reference):弱應用物件與軟引用物件的最大不同就在於:GC在進行垃圾回收時,需要通過演算法檢查是否回收Soft應用物件,而對於Weak引用,GC總是進行回收。Weak引用物件更容易、更快地被GC回收。Weak引用物件常常用於Map結構中。

import java.lang.ref.WeakReference;   4.                               ...   5.                                  6.                               A a = new A();   7.                               ...   8.  9.                               // 使用a   10.                               ...   11.                                   12.                               // 使用完了a, 將它設定為Weak引用型別,並且釋放強引用   13.                               WeakReference wr = new WeakReference(a);   14.                               a = null;   15.                               ...   16.  17.                               // 下次使用時   18.                if (wr != null) {   19.                    a = wr.get();   20.            } else {   21.                                   a = new A();   22.                wr = new WeakReference(a);   23.            } 

 虛引用(Phantom Reference): 虛引用的用途較少,主要用於輔助finalize函式的使用。 

虛引用(Phantom Reference)物件指一些執行完了finalize函式,併為不可達物件,但是還沒有被GC回收的物件。這種物件可以輔助finalize進行一些後期的回收工作,我們通過覆蓋了Refernce的clear()方法,增強資源回收機制的靈活性。 

       
       在實際程式設計中一般很少使用弱引用和虛引用,是用軟引用的情況較多,因為軟引用可以加速JVM對垃圾記憶體的回收速度,可以維護系統的執行安全,防止記憶體溢位(OutOfMemory)等問題的產生。 


    (3) 不可視階段 
         當一個物件處於不可視階段,說明我們在其他區域的程式碼中已經不可以在引用它,其強引用已經消失,例如,本地變數超出了其可視 
的範圍。 

     

1.try {   2.            Object localObj = new Object();   3.     localObj.doSomething();   4.      } catch (Exception e) {   5.          e.printStackTrace();   6.      }   7 8.      if (true) {   9.   

相關推薦

java物件初始回收

物件的初始化和回收         系統生成物件時,會自動為物件分配記憶體空間,並呼叫相應的建構函式對其初始化,在物件沒有任何引用繫結時,垃圾回收器會週期行掃描記憶體情況並進行回收。 初始化         物件的生成和初始化是一體的概念,生成了物件就會對其初始化。Ja

物件初始GC

構造方法constructor  用於物件的初始化 1.通過new關鍵字呼叫! 2.構造器雖然有返回值,但不能定義返回值型別。 3.構造器名和類名相同 4.如果我們沒有定義構造器,則編譯器會自動定義一個無參構造 垃圾回收機制

記一次使用Jackson對Java物件序列反序列的踩坑經歷

背景大概是這樣,專案中的兩個服務A和B依賴了同一個common包的Java類,A對該類json序列化,而B對其反序列化。在一次common包升級過程中,這個Java類中增加了一個屬性,由於B其實用不到這個屬性,就只把A給升級打包了,這就導致B在反序列化時出現了一個異常:com.fasterxml.j

Java初始例項

摘要: Java有以下幾種方式建立類物件: 利用new關鍵字 利用反射Class.newInstance 利用Constructor.newIntance(相比Class.newInstance多了有參和私有建構函式) 利用Cloneable/Object.clone() 利

Java 物件序列反序列 (實現 Serializable 介面)

序列化和反序列化的概念 把物件轉換為位元組序列的過程稱為物件的序列化。 把位元組序列恢復為物件的過程稱為物件的反序列化。 物件的序列化主要有兩種用途: 把物件的位元組序列永久地儲存到硬碟上,通常存放在一個檔案中; 在網路上傳送物件的位元組序列。 JDK

Java 物件初始順序 執行順序

先看一道Java面試題: 求這段程式的輸出。 解答此題關鍵在於理解和掌握類的載入過程以及子類繼承父類後,重寫方法的呼叫問題: 從程式的執行順序去解答: 1.編譯;當這個類被編譯通知後,會在相應的

java物件初始過程

假設有一下類: class Test{ int i; int j = 0; int count(){ return 0 }; Test() {} int n =0; } 我們知道,任何物件在使用前都會被初始化,方法裡

Java基礎學習系列-Java初始例項

Java有以下幾種方式建立類物件: 利用new關鍵字 利用反射Class.newInstance 利用Constructor.newIntance(相比Class.newInstance多了有參和私有建構函式) 利用Cloneable/Object.clon

java 建立物件的四種方式、java物件初始順序

java建立物件的幾種方式: (1) 用new語句建立物件,這是最常見的建立物件的方法。 (2) 運用反射手段,呼叫java.lang.Class或者java.lang.reflect.Const

java 物件序列物件反序列操作時的版本相容性問題

當你一個類實現了Serializable介面,如果沒有定義serialVersionUID,Eclipse會提供這個提示功能告訴你去定義 。在Eclipse中點選類中warning的圖示一下,Eclipse就會自動給定兩種生成的方式。如果你沒有考慮到相容性問題時,就把它關掉,不過有這個功能是好的,只要任何類別

Java——物件初始順序

一、 程式碼塊的概念 在探究物件初始化順序之前,我們先通過程式碼來了解一下程式碼塊的概念。 class Test{ public static String str1; //靜態欄位 public String str2;

java初始清理

初始化: java中使用構造器來確保初始化,構造器採用和類相同的名稱,在建立物件的時候呼叫構造器,為物件分配儲存空間。如果自己沒有寫構造器,編譯器會自動加入一個構造器以確保初始化。 構造器沒有返回值,和一般的方法不同。 預設構造器(無參構造器):不接受任何引數。 如果在一個

(二)遠端服務:Java 物件序列反序列

在遠端方法呼叫 RMI 學習的過程中,涉及到一個概念,序列化,本文進行詳述。 Java 物件的序列化和反序列化 的兩種應用場景 有時候需要將 Java 物件儲存永久儲存,比如儲存到檔

一文理解java物件初始順序

例子 ​ Talk is cheap, Show you the code! public class ParentClass { static int parentStaticField = 1; final static int parentFinalStaticField =

Java物件陣列的靜態初始動態初始

物件陣列 物件陣列的元素為引用資料型別,例如類,介面 和基本資料型別一樣,物件陣列初始化也分為靜態初始化,動態初始化兩種 物件陣列動態初始化 //定義Person類 class Pe

java中類的初始物件的例項區別

在程式RUN的一瞬間,什麼類啊,靜態的東西啊(靜態塊,靜態方法,靜態屬性),刷刷刷的就在記憶體中載入(你可以看作初始化)了,只加載一次,然後main方法開始執行(這就是為什麼main方法必須是靜態的原

java物件初始清理

初始化和清理 對於初始化和清理(cleanup),C++引入了構造器(constructor)的概念,這是一個在建立物件時被自動呼叫的特殊方法,Java也採用了構造器,並額外提供了“垃圾回收器”; 1、使用構造器確保初始化 (1)Java中每個類都會有一個initial

Java基礎:初始清理

class mil key java基礎 一個 add one his span 轉載請註明出處:jiq?欽‘s technical Blog (1) 初始化:所以假設繼承關系為:A導出B再導出C,在創建C對象的情況下的調用順序是: * (1) A的靜態域,B的靜態域

static類變數與物件初始載入時機

1.static修飾的範圍 使用範圍:在Java類中,可用static修飾屬性、方法、程式碼塊、內部類 被修飾後的成員具備以下特點: 隨著類的載入而載入 優先於物件存在 修飾的成員,被所有物件所共享 訪問許可權允許時,可不建立物件,直接被類呼叫 2.類變數(cla

Java物件深度複製序列總結

經常會碰到物件複製的問題,這個問題比較基礎,同時與JVM記憶體模型掛鉤。 1. 實現Cloneable介面預設的clone方法是淺拷貝 Java Cloneable介面實際上是個空介面,沒有任何方法,實際的clone()是object的方法,但是是一個protected的方法,因此需