溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java中會存在內(nèi)存泄漏嗎

發(fā)布時間:2021-08-26 14:19:02 來源:億速云 閱讀:147 作者:chen 欄目:編程語言

這篇文章主要介紹“java中會存在內(nèi)存泄漏嗎”,在日常操作中,相信很多人在java中會存在內(nèi)存泄漏嗎問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”java中會存在內(nèi)存泄漏嗎”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

所謂內(nèi)存泄露就是指一個不再被程序使用的對象或變量一直被占據(jù)在內(nèi)存中。java 中有垃圾回收機(jī)制,它可以保證一對象不再被引用的時候,即對象編程了孤兒的時候,對象將自動被垃圾回收器從內(nèi)存中清除掉。由于 Java 使用有向圖的方式進(jìn)行垃圾回收管理,可以消除引用循環(huán)的問題,例如有兩個對象,相互引用,只要它們和根進(jìn)程不可達(dá)的,那么 GC 也是可以回收它們的,例如下面的代碼可以看到這種情況的內(nèi)存回收:

package com.huawei.interview;
 
import java.io.IOException;
 
publicclass GarbageTest {
 
 /**
 * @paramargs
 * @throwsIOException
 */
 public static voidmain(String[] args)throws IOException {
 // TODO Auto-generated method stub
 try { 
 gcTest();
 } catch (IOException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } 
     System.out.println("hasexited gcTest!");
     System.in.read();
     System.in.read(); 
     System.out.println("out begingc!"); 
   for(int i=0;i<100;i++){ 
     System.gc();
     System.in.read();
     System.in.read();
   } 
 } 
 
 private static voidgcTest()throws IOException {
       System.in.read();
       System.in.read(); 
       Person p1 = new Person();
       System.in.read();
       System.in.read(); 
       Person p2 = new Person();
       p1.setMate(p2);
       p2.setMate(p1);
       System.out.println("beforeexit gctest!");
       System.in.read();
       System.in.read(); 
       System.gc();
       System.out.println("exitgctest!");
 } 
 
 private static classPerson{ 
      byte[] data =new byte[20000000];
      Person mate = null; 
    public void setMate(Personother){ 
        mate = other;
      } 

 } 
}

java 中的內(nèi)存泄露的情況:長生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內(nèi)存泄露,盡管短生命周期對象已經(jīng)不再需要,但是因為長生命周期對象持有它的引用而導(dǎo)致不能被回收,這就是 java 中內(nèi)存泄露的發(fā)生場景,通俗地說,就是程序員可能創(chuàng)建了一個對象,以后一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是 java 中可能出現(xiàn)內(nèi)存泄露的情況,例如,緩存系統(tǒng),我們加載了一個對象放在緩存中(例如放在一個全局 map 對象中),然后一直不再使用它,這個對象一直被緩存引用,但卻不再被使用。

檢查 java 中的內(nèi)存泄露,一定要讓程序?qū)⒏鞣N分支情況都完整執(zhí)行到程序結(jié)束,然后看某個對象是否被使用過,如果沒有,則才能判定這個對象屬于內(nèi)存泄露。

如果一個外部類的實(shí)例對象的方法返回了一個內(nèi)部類的實(shí)例對象,這個內(nèi)部類對象被長期引用了,即使那個外部類實(shí)例對象不再被使用,但由于內(nèi)部類持久外部類的實(shí)例對象,這個外部類對象將不會被垃圾回收,這也會造成內(nèi)存泄露。

下面內(nèi)容來自于網(wǎng)上(主要特點(diǎn)就是清空堆棧中的某個元素,并不是徹底把它從數(shù)組中拿掉,而是把存儲的總數(shù)減少,本人寫得可以比這個好,在拿掉某個元素時,順便也讓它從數(shù)組中消失,將那個元素所在的位置的值設(shè)置為 null 即可):

我實(shí)在想不到比那個堆棧更經(jīng)典的例子了,以致于我還要引用別人的例子,下面的例子不是我想到的,是書上看到的,當(dāng)然如果沒有在書上看到,可能過一段時間我自己也想的到,可是那時我說是我自己想到的也沒有人相信的。

public class Stack {
    private Object[] elements=new Object[10];
    private int size = 0;
 public void push(Object e){
     ensureCapacity();
     elements[size++] = e;
 } 
 public Object pop(){
    if( size == 0)
    throw new EmptyStackException();
    return elements[--size];
 } 
 private void ensureCapacity(){
    if(elements.length == size){
      Object[] oldElements = elements;
      elements = new Object[2 * elements.length+1];
     System.arraycopy(oldElements,0, elements, 0, size);
      } 
    } 
 }

上面的原理應(yīng)該很簡單,假如堆棧加了10個元素,然后全部彈出來,雖然堆棧是空的,沒有我們要的東西,但是這是個對象是無法回收的,這個才符合了內(nèi)存泄露的兩個條件:無用,無法回收。
但是就是存在這樣的東西也不一定會導(dǎo)致什么樣的后果,如果這個堆棧用的比較少,也就浪費(fèi)了幾個 K 內(nèi)存而已,反正我們的內(nèi)存都上 G 了,哪里會有什么影響,再說這個東西
很快就會被回收的,有什么關(guān)系。下面看兩個例子。

public class Bad{
   public static Stack s=Stack();
    static{ 
      s.push(new Object());
      s.pop(); //這里有一個對象發(fā)生內(nèi)存泄露
      s.push(new Object()); //上面的對象可以被回收了,等于是自愈了
    } 
 }

因為是 static,就一直存在到程序退出,但是我們也可以看到它有自愈功能,就是說如果你的 Stack 最多有100個對象,那么最多也就只有100個對象無法被回收其實(shí)這個應(yīng)該很容易理解,Stack 內(nèi)部持有100個引用,最壞的情況就是他們都是無用的,因為我們一旦放新的進(jìn)取,以前的引用自然消失!

內(nèi)存泄露的另外一種情況:當(dāng)一個對象被存儲進(jìn) HashSet 集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了,否則,對象修改后的哈希值與最初存儲進(jìn) HashSet
集合中時的哈希值就不同了,在這種情況下,即使在contains 方法使用該對象的當(dāng)前引用作為的參數(shù)去 HashSet 集合中檢索對象,也將返回找不到對象的結(jié)果,這也會導(dǎo)致無法從HashSet 集合中單獨(dú)刪除當(dāng)前對象,造成內(nèi)存泄露。

到此,關(guān)于“java中會存在內(nèi)存泄漏嗎”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI