在使用對象時,最關鍵的問題之一便是他們的生成和銷毀方式。每個對象為了生存都需要資源,尤其是內存。當我們不需要一個對象時,它必須被處理掉,使其占有的資源必須被釋放和重用。
在相對簡單的編程情況下,怎樣清理對象看起來似乎不是什么難事,你創建了對象,根據需要使用它,然后他應該被銷毀。你可能遇到相對復雜的情況。
例如:假設你正在為某個機場設計交通管理系統,一開始問題似乎很簡單:創建一個容器來保存所有飛機,然后為每個飛機創建一個對象,並將其置於容器中,對於清理工作,只需在飛機離開時刪除相關飛機對象即可。但是可能別的系統也記錄這有關的飛機的數據,也許這些數據不需要像主要控制功能那樣立即引人注意。例如,他可能記錄着所有飛離機場的小型飛機的飛行計划,因此你需要有第二個容器來存放小型飛機;無論何時,只要創建的是小型飛機對象,那么它同時也應該放入第二個人容器內。然后某個后台進程空閑時對第二個容器內的對象進行操作。
現在問題變得困難了:怎樣才能知道何時銷毀這些對象呢?當處理完某個對象之后,系統某個其它部分可能還在處理它。在其他很多場合中也會遇到同樣的問題,在必須明確刪除對象的編程系統中(例如:C++),此問題會變得十分麻煩。
對象的數據位於何處?怎樣控制對象的聲明周期?C++ 認為效率控制是最重要的議題,所以給程序員提供了選擇的權利。為了追求最大的執行速度,對象的存儲空間和生命周期可以在編寫程序時確定,這可以將對象置於堆棧(它們優勢被稱為自動變量(automatic variable)或限域變量(scoped variable))或靜態存儲區域內來實現。這種方式將存儲空間分配和釋放置於優先考慮的位置,某些情況下這樣控制非常有價值。但是也犧牲了靈活性。因為必須在編寫程序時知道對象確切的數量、生命周期和類型。如果試圖解決更一般化的問題,例如計算機輔助設計、倉庫管理或者空中交通控制,這種方式就顯得過於受限了。
第二種方式是在被稱為對(heap)的內存池中動態的創建對象。在這種方式中,知道運行時才知道需要多少對象,它們的生命周期如何,以及它們的具體類型是什么。這些問題的答案只能在程序運行時相關代碼被執行到的那一刻才能確定。如果需要一個對象,可以在需要的時候直接在堆中創建。因為存儲空間運行的時候是被動態管理的,所以需要大量的時間在堆中分配存儲空間,這可能要遠遠大於在堆棧中創建存儲空間的時間。在堆棧中創建存儲空間和釋放存儲空間通常各需要一條匯編指令即可,分別對應將棧頂指針向下移動和將棧頂指針向上移動。創建堆存儲空間的的時間依賴於存儲機制的設計。
動態方式有這樣一個一般性的邏輯假設:對象趨向於變得復雜,對於查找和釋放存儲空間的開銷不會對對象的創建造成重大打擊。動態方式所帶來的更大的靈活性正是解決一般化編程問題的要點所在。
Java 完全采用了動態內存分配方式。每當想要創建新對象時,就要使用 new 關鍵字來構建此對象的動態實例。
還有一個議題,就是對象的生命周期。對於允許在堆上創建對象的編程語言,編譯器可以確定對象存活的時間,並可以自動銷毀它。然而,如果在棧上創建對象,編譯器就會對它的生命周期一無所知。在像 C++ 這樣的語言中,必須通過編程方式來確定何時銷毀對象,這可能會因為不能正確處理而導致內存泄露(C++ 程序中的家常便飯)。Java 提供了被稱為“垃圾回收器”的機制,它可以自動發現對象何時不再使用,並繼而銷毀它。垃圾回收器非常有用,因為它減少了所必須考慮的議題和必須編寫得代碼。更重要的是,垃圾回收器提供了更高層的保障,可以避免暗藏的內存泄露問題,這個問題已經使許多 C++ 項目折戟沉沙。
Java 的垃圾回收器被設計用來處理內存釋放問題(盡管它不包括清理對象的其他方面)。垃圾回收器“知道”對象何時不再被使用,並自動釋放對象占用的內存。這一點同所有對象都是繼承自單根基類 Object 以及只能以一種方式創建對象(在堆上創建)這兩個特性結合起來,使得 Java 編程的過程跟 C++ 相比要簡單得多,所以要做出的決策和要克服的障礙也要少很多。