熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

詳解JVM的內存管理機制

2022-06-13   來源: Java核心技術 
我們在深入Java核心系列文章中給大家講過JVM中的棧和局部變量在做Java開發的時候常用的JVM內存管理有兩種一種是堆內存一種是棧內存堆內存主要用來存儲程序在運行時創建或實例化的對象與變量例如我們通過new MyClass()創建的類MyClass的對象而棧內存則是用來存儲程序代碼中聲明為靜態(或非靜態)的方法下面我給大家舉個例子
 
  就拿上面的例子來說放在棧內存中的有mainmakeThings放在堆內存中有Testlistobject
  JVM中對象的生命周期大致可以分為個階段創建階段應用階段不可視階段不可到達階段可收集階段終結階段與釋放階段
 創建階段
  ()為對象分配存儲空間
  ()開始構造對象
  ()遞歸調用其超類的構造方法
  ()進行對象實力初始化與變量初始化
  ()執行構造方法體
  還有就是你在創建對象的時候需要注意的地方
  ()避免在循環體中創建對象即使該對象占用內存空間不大
  ()盡量及時使對象符合垃圾回收標准
  ()不要采用過深的繼承層次
  ()訪問本地變量優於訪問類中的變量
 應用階段
  在應用階段涉及到個引用
  ()強引用是指JVM內存管理器從根引用集合出發遍尋堆中所有到達對象的路徑
  ()軟引用是具有較強的引用功能只有當內存不夠的時候才回收這類內存因此內存足夠的時候不會被回收
  ()弱引用弱引用與軟引用對象的最大不同在於GC在進行回收時需要通過算法檢查是否回收軟引用對象而對於弱引用來說GC總是進行回收
  ()虛引用主要用於輔助finalize函數的使用虛引用主要適用於以某種比Java終結機制更靈活的方式調度premortem清除操作


  不可視階段
  先看一段代碼
 
  如果一個對象已使用完了應該主動將其設置為null可以在上面的代碼行objdoSomething();下添加代碼行obj=null;這樣一行代碼強制將obj對象置為空值這樣做的意義就是幫助JVM及時的發現這個垃圾對象並且可以及時的回收該對象占用的系統資源
  不可到達階段
  處於不可到達階段的對象在虛擬機所管理的對象引用根集合中再也找不到直接或間接的強引用這些對象通常是指多有線程棧中的臨時變量所有已裝載的類的靜態變量或者對本地代碼接口(JNI)引用
  可收集階段終結階段與釋放階段
  當對象處於這個階段的時候可能處於下面三種情況
  ()垃圾回收器發現該對象已經不可到達
  ()finalize方法已經被執行
  ()對象空間已被重用
  當對象處於上面三種清空的時候虛擬機就可以直接將該對象回收了
  析構方法finalize
  前面我們說了JVM的垃圾回收機制和JVM中對象的生命周期今天給大家講個方法叫做析構方法finalize我想搞過C++的人都知道而且是內存管理技術中相當重要的一部分但是在Java中好像沒有這個概念這是因為理論上JVM負責對象的析構(銷毀與回收)工作finalize是Object類中的一個方法並且是protected由於所有的類都繼承了Object對象因此就都隱式的繼承了改方法不過可以重寫這個方法如果重寫此方法最後一句必須寫上superfinalize()語句因為finalize方法沒有自動實現遞歸調用那我們在什麼時候要重寫它呢?當有一些不容易控制並且非常重要的資源時要放到finalize方法中例如一些I/O的操作數據的連接等等這些資源的釋放對整個應用程序是非常關鍵的


  我先讓大家看一段代碼
 
  finalize方法最終是由JVM中的垃圾回收器調用的由於垃圾回收器調用finalize的時間是不確定或者不及時的調用時機對我們來說是不可控的因此我們可以在自己的類中聲明一個destory()方法在這個方法中添加釋放系統資源的處理代碼但是還是建議你將對destroy()方法的調用放入當前類的finalize()方法體中因為這樣做更保險更安全
  靜態變量
  我們知道類中的靜態變量在程序運行期間其內存空間對所有該類的對象實例而言是共享的為了節省系統內存開銷共享資源應該將一些變量聲明為靜態變量通過下面的例子你就會發現有什麼不同
  代碼一
 


  代碼二
 
  我想大家應該發現上面那兩個類的區別了吧!
  代碼一會在內存中保存個weeks的副本而代碼二則在內存中保存個weeks的副本然後共享該副本這樣的話就不會造成內存的浪費
  雖然靜態的變量能節約大量的內存但是並不是所有的地方都適合用建議大家在下列條件都符合的情況下盡量用靜態變量
  ()變量所包含的對象體積較大占用內存較多
  ()變量所包含的對象生命周期較長
  ()變量所包含的對象數據穩定
  ()該類的對象實例有對該變量所包含的對象的共享需求
  如果變量不具備上述特點建議不要輕易使用靜態變量以免弄巧成拙
  最後再提一點內存的優化就是有關對象的重用比如對象池和數據庫連接池等那樣的話是很節約內存空間的不過在用的時候要考慮各個方面比如運行環境的內存資源的限制等為了防止對象池中的對象過多要記得清除


  內存管理有許多技巧和方式
  其實內存管理有許多技巧和方式在這我給大家介紹一下
  ()要盡早的釋放無用對象的引用如果該對象不用了你可以把它設置為null但要注意如果該對象是某方法的返回值千萬不要這樣處理否則你從該方法中得到的返回值永遠為空而且這種錯誤不易被發現因此這時很難及時抓住排除NullPointerException異常
  ()盡量少用finalize函數因為它會加大GC的工作量因此盡量少用finalize方式回收資源
  ()如果需要使用經常用到的圖片可以使用soft應用類型(也就是轉換為軟引用類型)它可以盡可能將圖片保存在內存中供程序調用而不引起OutOfMemory
  ()注意集合數據類型包括數組鏈表等數據結構這些數據結構對於GC來說回收更為復雜另外要注意那些全局變量靜態變量這些對象往往容易引起懸掛對象造成內存浪費
  ()盡量避免在類的默認構造器中創建初始化大量的對象防止在調用其子類的構造器時造成不必要的內存資源浪費
  ()盡量避免強制系統做垃圾內存回收(通過顯式調用方法Systemgc())增長系統做垃圾回收的最終時間降低系統性能
  ()盡量避免顯式申請數組空間當不得不顯式申請數組空間時盡量准確的估計出其合理值以免造成不必要的系統內存開銷
  ()盡量在做遠程方法調用(RMI)類應用開發時使用瞬間值變量除非遠程調用端需要獲取該瞬間值變量的值
  ()盡量在合適的場景下使用對象池技術以提高系統的性能縮減系統內存開銷但是要注意對象池的尺寸不易過大及時清除無效對象釋放內存資源綜合考慮應用運行環境的內存資源限制避免過高估計運行環境所提供內存資源的數量
  雖然這些技巧提高不了多少性能但是在嵌入式開發或者要求性能比較高的系統中卻很有用


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26573.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.