這篇文章主要介紹“java中會存在內存泄漏嗎”,在日常操作中,相信很多人在java中會存在內存泄漏嗎問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”java中會存在內存泄漏嗎”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
所謂內存泄露就是指一個不再被程序使用的對象或變量一直被占據在內存中。java 中有垃圾回收機制,它可以保證一對象不再被引用的時候,即對象編程了孤兒的時候,對象將自動被垃圾回收器從內存中清除掉。由于 Java 使用有向圖的方式進行垃圾回收管理,可以消除引用循環的問題,例如有兩個對象,相互引用,只要它們和根進程不可達的,那么 GC 也是可以回收它們的,例如下面的代碼可以看到這種情況的內存回收:
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 中的內存泄露的情況:長生命周期的對象持有短生命周期對象的引用就很可能發生內存泄露,盡管短生命周期對象已經不再需要,但是因為長生命周期對象持有它的引用而導致不能被回收,這就是 java 中內存泄露的發生場景,通俗地說,就是程序員可能創建了一個對象,以后一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是 java 中可能出現內存泄露的情況,例如,緩存系統,我們加載了一個對象放在緩存中(例如放在一個全局 map 對象中),然后一直不再使用它,這個對象一直被緩存引用,但卻不再被使用。
檢查 java 中的內存泄露,一定要讓程序將各種分支情況都完整執行到程序結束,然后看某個對象是否被使用過,如果沒有,則才能判定這個對象屬于內存泄露。
如果一個外部類的實例對象的方法返回了一個內部類的實例對象,這個內部類對象被長期引用了,即使那個外部類實例對象不再被使用,但由于內部類持久外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會造成內存泄露。
下面內容來自于網上(主要特點就是清空堆棧中的某個元素,并不是徹底把它從數組中拿掉,而是把存儲的總數減少,本人寫得可以比這個好,在拿掉某個元素時,順便也讓它從數組中消失,將那個元素所在的位置的值設置為 null 即可):
我實在想不到比那個堆棧更經典的例子了,以致于我還要引用別人的例子,下面的例子不是我想到的,是書上看到的,當然如果沒有在書上看到,可能過一段時間我自己也想的到,可是那時我說是我自己想到的也沒有人相信的。
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); } } }
上面的原理應該很簡單,假如堆棧加了10個元素,然后全部彈出來,雖然堆棧是空的,沒有我們要的東西,但是這是個對象是無法回收的,這個才符合了內存泄露的兩個條件:無用,無法回收。
但是就是存在這樣的東西也不一定會導致什么樣的后果,如果這個堆棧用的比較少,也就浪費了幾個 K 內存而已,反正我們的內存都上 G 了,哪里會有什么影響,再說這個東西
很快就會被回收的,有什么關系。下面看兩個例子。
public class Bad{ public static Stack s=Stack(); static{ s.push(new Object()); s.pop(); //這里有一個對象發生內存泄露 s.push(new Object()); //上面的對象可以被回收了,等于是自愈了 } }
因為是 static,就一直存在到程序退出,但是我們也可以看到它有自愈功能,就是說如果你的 Stack 最多有100個對象,那么最多也就只有100個對象無法被回收其實這個應該很容易理解,Stack 內部持有100個引用,最壞的情況就是他們都是無用的,因為我們一旦放新的進取,以前的引用自然消失!
內存泄露的另外一種情況:當一個對象被存儲進 HashSet 集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了,否則,對象修改后的哈希值與最初存儲進 HashSet
集合中時的哈希值就不同了,在這種情況下,即使在contains 方法使用該對象的當前引用作為的參數去 HashSet 集合中檢索對象,也將返回找不到對象的結果,這也會導致無法從HashSet 集合中單獨刪除當前對象,造成內存泄露。
到此,關于“java中會存在內存泄漏嗎”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。