日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

2.Java内存回收机制

發(fā)布時間:2025/3/15 java 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2.Java内存回收机制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、Java對象在內(nèi)存引用狀態(tài)

內(nèi)存泄露:程序運行過程中,會不斷分配內(nèi)存空間,那些不再使用的內(nèi)存空間應(yīng)該即時回收它們,從而保證系統(tǒng)可以再次使用這些內(nèi)存,如果存在無用的內(nèi)存沒有被回收回來,這就是內(nèi)存泄漏.
(1)強引用
  這是java程序中最常見的引用方式,程序創(chuàng)建一個對象,并把這個對象賦給一個引用變量,這個引用變量就是強引用.java程序可通過強引用來訪問實際的對象。當(dāng)一個對象被一個或一個以上的強引用變量引用時,它處于可達狀態(tài),它不可能被系統(tǒng)垃圾回收機制回收。
  強引用是Java編程中廣泛使用的引用類型,被強引用所引用的Java對象絕不會被垃圾回收機制回收,即使系統(tǒng)內(nèi)存緊張;即使有些Java對象以后永遠也不會被用到,JVM也不會回收被強引用所引用的Java對象.
  由于JVM肯定不會回收強引用所引用的JAVA對象,因此強引用是造成JAVA內(nèi)存泄漏的主要原因。
    如 ReceiptBean rb=new ReceiptBean(); rb就代表了一種強引用的方式
(2)軟引用
  軟引用需要通過SoftReference類來實現(xiàn),當(dāng)一個對象只具有軟引用時,它可能被垃圾回收機制回收。對于只有軟引用的對象而言,當(dāng)系統(tǒng)內(nèi)存空間足夠時,它不會被系統(tǒng)回收,程序也可以使用該對象;當(dāng)系統(tǒng)內(nèi)存空間不足時,系統(tǒng)將回收它.
  軟引用通常用在對內(nèi)存敏感的程序中,軟引用是強引用很好的替代。對于軟引用,當(dāng)系統(tǒng)內(nèi)存空間充足時,軟引用與強引用沒有太大的區(qū)別,當(dāng)系統(tǒng)內(nèi)存空間不足時,被軟引用所引用的JAVA對象可以被垃圾回收機制回收,從而避免系統(tǒng)內(nèi)存不足的異常.
  當(dāng)程序需要大量創(chuàng)建某個類的新對象,而且有可能重新訪問已創(chuàng)建老對象時,可以充分使用軟引用來解決內(nèi)存緊張的問題。

例如需要訪問1000個Person對象,可以有兩種方式
方法一
依次創(chuàng)建1000個對象,但只有一個Person引用指向最后一個Person對象
方法二 定義一個長度為1000個的Person數(shù)組,每個數(shù)組元素引用一個Person對象.

對于方法一,弱點很明顯,程序不允許需要重新訪問前面創(chuàng)建的Person對象,即使這個對象所占的空間還沒有被回收。但已經(jīng)失去了這個對象的引用,因此也不得不重新創(chuàng)建一個新的Person對象(重新分配內(nèi)存),而那個已有的Person對象(完整的,正確的,可用的)則只能等待垃圾回收
對于方法二,優(yōu)勢是可以隨時重新訪問前面創(chuàng)建的每個Person對象,但弱點也有,如果系統(tǒng)堆內(nèi)存空間緊張,而1000個Person對象都被強引用引著,垃圾回收機制也不可能回收它們的堆內(nèi)存空間,系統(tǒng)性能將變成非常差,甚至因此內(nèi)存不足導(dǎo)致程序中止。

  如果用軟引用則是一種較好的方案,當(dāng)堆內(nèi)存空間足夠時,垃圾回收機制不會回收Person對象,可以隨時重新訪問一個已有的Person對象,這和普通的強引用沒有任何區(qū)別。但當(dāng)heap堆內(nèi)存空間不足時,系統(tǒng)也可以回收軟引用引用的Person對象,從而提高程序運行性能,避免垃圾回收.

當(dāng)程序使用強引用時,無論系統(tǒng)堆內(nèi)存如何緊張,JVM垃圾回收機制都不會回收被強引用所引用的Java對象,因此最后導(dǎo)致程序因內(nèi)存不足而中止。但如果把強引用改為軟引用,就完成可以避免這種情況,這就是軟引用的優(yōu)勢所在.

(3)弱引用
  弱引用與軟引用有點相似,區(qū)別在于弱引用所引用對象的生存期更短。弱引用通過WeakReference類實現(xiàn),弱引用和軟引用很像,但弱引用的引用級別更低。對于只有弱引用的對象而言,當(dāng)系統(tǒng)垃圾回收機制運行時,不管系統(tǒng)內(nèi)存是否足夠,總會回收該對象所占用的內(nèi)存。當(dāng)然,并不是說當(dāng)一個對象只有弱引用時,它就會立即被回收,正如那些失去引用的對象一樣,必須等到系統(tǒng)垃圾回收機制運行時才會被回收.

總結(jié)說明:

1.弱引用具有很大的不確定性,因為每次垃圾回收機制執(zhí)行時都會回收弱引用所引用的對象,而垃圾回收機制的運行又不受程序員的控制,因此程序獲取弱引用所引用的java對象時必須小心空指針異常,通過弱引用所獲取的java對象可能是null

2.由于垃圾回收的不確定性,當(dāng)程序希望從弱引用中取出被引用對象時,可能這個被引用對象已經(jīng)被釋放了。如果程序需要使用被引用的對象,則必須重新創(chuàng)建該對象。

(4)虛引用
  軟引用和弱引用可以單獨使用,但虛引用不能單獨使用,單獨使用虛引用沒有太大的意義。虛引用的主要作用就是跟蹤對象被垃圾回收的狀態(tài),程序可以通過檢查虛引用關(guān)聯(lián)的引用隊列中是否包含指定的虛引用,從而了解虛引用所引用的對象是否將被回收.
  引用隊列由java.lang.ref.ReferenceQueue類表示,它用于保存被回收對象的引用。當(dāng)把軟引用,弱引用和引用隊列聯(lián)合使用時,系統(tǒng)回收被引用的對象之后,將會把被回收對象對應(yīng)的引用添加到關(guān)聯(lián)的引用隊列中。與軟引用和弱引用不同的是,虛引用在對象被釋放之前,將把它對應(yīng)的虛引用添加到關(guān)聯(lián)的隊列中,這使得可以在對象被回收之前采取行動。
虛引用通過PhantomReference類實現(xiàn),它完全類似于沒有引用。虛引用對對象本身沒有大的影響,對象甚至感覺不到虛引用的存在。如果一個對象只有一個虛引用,那它和沒有引用的效果大致相同。虛引用主要用于跟蹤對象被垃圾回收的狀態(tài),虛引用不能單獨使用,虛引用必須和隊列ReferenceQueue聯(lián)合使用.

二、Java內(nèi)存泄露

對于c++程序來說,對象占用的內(nèi)存空間都必須由程序顯式回收,如果程序員忘記了回收它們,那它們所占用的內(nèi)存空間就會產(chǎn)生內(nèi)存泄漏;對于java程序來說,所有不可達的對象都由垃圾回收機制負責(zé)回收,因此程序員不需要考慮這部分的內(nèi)存泄漏。但如果程序中有一些java對象,它們處于可達狀態(tài),但程序以后永遠都不會再訪問它們,那它們所占用的空間也不會被回收,它們所占用的空間也會產(chǎn)生內(nèi)存泄漏.

例如:
有ArrayList的長度是4,有四個元素“網(wǎng)”,“絡(luò)”,“時”,“空”,當(dāng)我們刪除了ArrayList中的"網(wǎng)"這個元素時,它的size等于3,也就是該ArrayList認為自己只有3個元素,因此它永遠也不會去訪問底層數(shù)組的第4個元素。對于程序本身來說,這個對象已經(jīng)變成了垃圾,但對于垃圾回收機制來說,這個對象依然處于可達狀態(tài),因此不會回收它,這就產(chǎn)生了內(nèi)存泄漏了 ?

再看下面程序采用基于數(shù)組的方式實現(xiàn)了一個Stack,大家可以找找這個程序中的內(nèi)存泄漏

?

package list;public class Stack {//存放棧內(nèi)元素的數(shù)組private Object[] elementData;//記錄棧內(nèi)元素的個數(shù)private int size = 0;private int capacityIncrement;//以指定初始化容量創(chuàng)建一個Stackpublic Stack(int initialCapacity){elementData = new Object[initialCapacity];}public Stack(int initialCapacity , int capacityIncrement){this(initialCapacity);this.capacityIncrement = capacityIncrement;}//向“?!表攭喝胍粋€元素public void push(Object object){ensureCapacity();elementData[size++] = object;// if(size==10) System.out.println("size="+size);}//出棧public Object pop(){if(size == 0){throw new RuntimeException("空棧異常");}return elementData[--size];}public int size(){return size;}//保證底層數(shù)組能容納棧內(nèi)所有元素private void ensureCapacity(){//增加堆棧的容量if(elementData.length==size){Object[] oldElements = elementData;int newLength = 0;//已經(jīng)設(shè)置capacityIncrementif (capacityIncrement > 0){newLength = elementData.length + capacityIncrement;}else{//將長度擴充到原來的1.5倍newLength = (int)(elementData.length * 1.5);}// System.out.println("newLength="+newLength);elementData = new Object[newLength];//將原數(shù)組的元素復(fù)制到新數(shù)組中System.arraycopy(oldElements , 0 , elementData , 0 , size);}}public static void main(String[] args){Stack stack = new Stack(10);//向棧頂壓入10個元素for (int i = 0 ; i < 10 ; i++){stack.push("元素" + i);}//依次彈出10個元素for (int i = 0 ; i < 10 ; i++){System.out.println(stack.pop());}} }

?

???? 前面程序?qū)崿F(xiàn)了一個簡單的Stack,并為這個Stack實現(xiàn)了push(),pop()兩個方法,其中pop()方法可能產(chǎn)生內(nèi)存泄漏。為了說明這個Stack的內(nèi)存泄漏,程序main方法創(chuàng)建了一個Stack對象,先向該Stack壓入10個元素。注意:此時底層elementData的長度為10,每人數(shù)組元素都引用一個字符串。
  接下來,程序10次調(diào)用pop()方法彈出棧頂元素。注意pop()方法產(chǎn)生的內(nèi)存泄漏,它只做了兩件事:一是修飾Stack的size屬性,也就是記錄棧內(nèi)元素減1,二是返回elementData數(shù)組中索引為size-1的元素

  也就是說,每調(diào)用pop方法一次,Stack會記錄該棧的尺寸減1,但未清除elementData數(shù)組的最后一個元素的引用,這樣就會產(chǎn)生內(nèi)存泄漏。類似地,也應(yīng)該按ArrayList類的源代碼改寫此處pop()方法的源代碼,如下所示
public Object pop()
{
if(size == 0)
{
throw new RuntimeException("空棧異常");
}
Object obj=elementData[--size];
//清除最后一個數(shù)組元素的引用,避免內(nèi)存泄漏
elementData[size]=null;
return obj;
}

三、內(nèi)存管理的小技巧

  盡可能多的掌握Java的內(nèi)存回收,垃圾回收機制是為了更好地管理JVM的內(nèi)存,這樣才能提高java程序的運行性能。根據(jù)前面介紹的內(nèi)存機制,下面給出java內(nèi)存管理的幾個小技巧。
(1)盡量使用直接量
  當(dāng)需要使用字符串,還有Byte,Short,Integer,Long,Float,Double,Boolean,Charater包裝類的實例時,程序不應(yīng)該采用new的方式來創(chuàng)建對象,而應(yīng)該直接采用直接量來創(chuàng)建它們。
例如,程序需要"hello"字符串,應(yīng)該采用如下代碼
String str="hello"'
上面這種方式創(chuàng)建一個"hello"字符串,而且JVM的字符串緩存池還會緩存這個字符串。但如果程序采用
String str=new String("hello");
  此時程序同樣創(chuàng)建了一個緩存在字符串緩存池中的"hello"字符串。除此之外,str所引用的String對象底層還包含一個char[]數(shù)組,這個char[]數(shù)組里依次存放了h,e,l,l.o等字符串。

(2)使用StringBuffer和StringBuilder進行字符串拼接
  如果程序中采用多個String對象進行字符串連接運算,在運行時將生成大量臨時字符串,這些字符串會保存在內(nèi)存中從而導(dǎo)致程序性能下降

(3)盡早釋放無用對象的引用
  大部分時候,方法局部引用變量所引用的對象會隨著方法結(jié)束而變成垃圾,因為局部變量的生存周期很短,當(dāng)方法運行結(jié)束之時,該方法內(nèi)的局部變量就結(jié)束了生命周期。因此,大部分時候程序無需將局部引用變量顯式設(shè)為null.
但是下面程序中的情形則需顯式設(shè)為null比較好了

public void info()
{
Object obj=new Objec();
System.out.println(obj.toString());
System.out.println(obj.toString());
obj=null;
//執(zhí)行耗時,耗內(nèi)存的操作
//或者調(diào)用耗時,耗內(nèi)存的操作的方法
..
}

  對于上面程序所示的info()方法,如果需要“執(zhí)行耗時,耗內(nèi)存的操作”或者"或者調(diào)用耗時,耗內(nèi)存的操作的方法",那么上面程序中顯式設(shè)置obj=null就是有必要的了??赡艿那闆r是:當(dāng)程序在“執(zhí)行耗時,耗內(nèi)存的操作”或者"或者調(diào)用耗時,耗內(nèi)存的操作的方法",obj之前所引用的對象可能被垃圾加收了。

(4)盡量少用靜態(tài)變量
  從理論來說,Java對象對象何時被回收由垃圾回收機制決定,對程序員來說是不確定的。由于垃圾回收機制判斷一個對象是否是垃圾的唯一標(biāo)準(zhǔn)就是該對象是否有引用變量引用它,因此要盡早釋放對象的引用。
  最壞的情況是某個對象被static變量所引用,那么垃圾回收機制通常是不會回收這個對象所占用的內(nèi)存的。

Class Person
{
static Object obj=new Object();
}
  對于上面的Object對象而言,只要obj變量還引用它,就會不會被垃圾回收機制所回收
Person類所對應(yīng)的Class對象會常駐內(nèi)存,直到程序結(jié)束,因此obj所引用的Object對象一旦被創(chuàng)建,也會常駐內(nèi)存,直到程序運行結(jié)束。

(5)避免在經(jīng)常調(diào)用的方法,循環(huán)中創(chuàng)建Java對象

public class Test
{
public static void main(String[] args)
{
for(int i=0;i<10;i++)
{
Object obj=new Object();
//執(zhí)行其它操作...
}
}
}

  上面物循環(huán)產(chǎn)生了10個對象,系統(tǒng)要不斷地為這些對象分配內(nèi)存空間,執(zhí)行初始化操作。它們的生存時間并不長,接下來系統(tǒng)又需要回收它們所占用的內(nèi)存空間是,這種不斷分配內(nèi)存,回收操作中,程序的性能受到了很大的影響。

(6)緩存經(jīng)常使用的對象
  如果有些對象需要經(jīng)常使用,可以考慮把這些對象用緩存池保存起來,這樣下次需要時就可直接拿出來這些對象來用。典型的緩存池是數(shù)據(jù)連接池,數(shù)據(jù)連接池里緩存了大量的數(shù)據(jù)庫連接,每次程序需要訪問數(shù)據(jù)庫時都可直接取出數(shù)據(jù)庫連接。
  除此之外,如果系統(tǒng)里還有一些常用的基礎(chǔ)信息,比如信息化信息里包含的員工信息,物料信息等,也可以考慮對它們進行緩存。
使用緩存通常有兩種方法
1.使用HashMap進行緩存
2.直接使用開源緩存項目。(如OSCache,Ehcahe等)

(7)盡量不要用finalize方法
  在一個對象失去引用之后,垃圾回收器準(zhǔn)備回收該對象之前,垃圾回收器會先調(diào)用對象的finalize()方法來執(zhí)行資源清理。出于這種考慮,可能有些開發(fā)者會考慮使用finalize()方法來進和清理。
在垃圾回收器本身已經(jīng)嚴重制約應(yīng)用程序性能的情況下,如果再選擇使用finalize方法進行資源清理,無疑是一種火上澆油的行為,這將導(dǎo)致垃圾回收器的負擔(dān)更大,導(dǎo)致程序運行效率更低

(8)考慮使用SoftReference軟引用
   

轉(zhuǎn)載于:https://www.cnblogs.com/jiutianhe/archive/2012/10/07/2755670.html

總結(jié)

以上是生活随笔為你收集整理的2.Java内存回收机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 玩日本老头很兴奋xxxx | 精品一区二区精品 | 玉女心经 在线 | 亚洲国产一区二区三区 | 中文亚洲字幕 | 韩国三级在线看 | 9191国产精品| 久久亚洲国产精品 | 久久久不卡国产精品一区二区 | 中文字幕一区二区三区波野结 | 另类ts人妖一区二区三区 | 大地资源影视在线播放观看高清视频 | 亚洲视频欧美视频 | 成人在线观看a | 国产学生美女无遮拦高潮视频 | 国内精品久久久 | 红桃视频91| 日本大胆裸体做爰视频 | 一边摸一边做爽的视频17国产 | 不许穿内裤随时挨c调教h苏绵 | 丰满人妻一区二区 | 另类在线视频 | 国产v综合v亚洲欧美久久 | 国产伦理久久精品久久久久 | 成人网av| 神马午夜伦理影院 | 麻豆一区在线 | 夜操操 | 天堂av在线资源 | 亚洲免费高清 | 久久一区欧美 | 亚洲精品一区二区18漫画 | 亚洲欧美另类日本 | 秋霞在线观看视频 | 国产成人91精品 | 亚洲经典在线观看 | 午夜毛片在线 | 青青操国产 | 欧美日韩一区二区三区在线播放 | www.av小说 | 久久久久久夜 | 国产传媒一区二区三区 | 欧美日韩在线观看免费 | 2023av在线| 久久精品aⅴ无码中文字字幕重口 | 人人爽人人插 | 伊人久久久久久久久久久 | 日本成人中文字幕 | 日韩高清不卡一区 | 日韩免费专区 | 日韩在线网址 | 日本精品一区二区在线观看 | 热re99久久精品国产99热 | 狂野欧美性猛交xxxx巴西 | 日韩国产欧美一区二区 | 中文字幕欧美视频 | 中国爆后菊女人的视频 | av小说免费在线观看 | 久久av一区二区三 | 三级影片在线播放 | 久草av在线播放 | 古代玷污糟蹋np高辣h文 | 久久久久国产一区二区 | 福利精品视频 | 成人手机看片 | 狠狠鲁视频 | 美日韩免费 | 制服丝袜第二页 | 性久久久久久久久 | 成人a v视频| 日韩毛片基地 | 人妻熟女aⅴ一区二区三区汇编 | 天天操夜夜拍 | 日本亚洲一区二区 | 国产中文字幕免费 | 男人的天堂日韩 | 欧美一区二区不卡视频 | 国产草草视频 | 丝袜人妻一区二区 | 天堂激情网| 国产激情四射 | 欧美偷拍视频 | 丁香六月久久 | 成年人久久| 五月天天 | 久久精品噜噜噜成人88aⅴ | 四虎在线播放 | 成人黄色一级片 | 中文字幕一区二区在线老色批影视 | 欧美一区二区三区免费 | 成人免费看片入口 | 欧美一区二区二区 | 亚洲色图激情小说 | 性色av一区二区 | 日本成人中文字幕 | 影音先锋一区 | 欧美另类z0z变态 | 综合xx网 | 久久影院午夜 |