一位面試官詢問我:Java中的JVM記憶體溢位和記憶體泄露是什么?我這么回答成功拿到了offer,
1. 記憶體泄漏(memory leak )
申請了記憶體用完了不釋放,比如一共有 1024M 的記憶體,分配了 521M 的記憶體一直不回收,那么可以用的記憶體只有 521M 了,仿佛泄露掉了一部分;
通俗一點講的話,記憶體泄漏就是【占著茅坑不拉shi】,
整理了最新2020整理收集的一線互聯網公司面試真題(都整理成檔案),有很多干貨,包含netty,spring,執行緒,spring cloud等詳細講解,也有詳細的學習規劃圖,面試題整理等,我感覺在面試這塊講的非常清楚:獲取面試資料只需:點擊這里領取!!!暗號:CSDN
2. 記憶體溢位(out of memory)
申請記憶體時,沒有足夠的記憶體可以使用;
通俗一點兒講,一個廁所就三個坑,有兩個站著茅坑不走的(記憶體泄漏),剩下最后一個坑,廁所表示接待壓力很大,這時候一下子來了兩個人,坑位(記憶體)就不夠了,記憶體泄漏變成記憶體溢位了,
可見,記憶體泄漏和記憶體溢位的關系:記憶體泄露的增多,最侄訓導致記憶體溢位,
這是一個很有味道的例子,

如上圖:
物件 X 參考物件 Y,X 的生命周期比 Y 的生命周期長;
那么當Y生命周期結束的時候,X依然參考著Y,這時候,垃圾回收期是不會回收物件Y的;
如果物件X還參考著生命周期比較短的A、B、C,物件A又參考著物件 a、b、c,這樣就可能造成大量無用的物件不能被回收,進而占據了記憶體資源,造成記憶體泄漏,直到記憶體溢位,
泄漏的分類
經常發生:發生記憶體泄露的代碼會被多次執行,每次執行,泄露一塊記憶體;
偶然發生:在某些特定情況下才會發生;
一次性:發生記憶體泄露的方法只會執行一次;
隱式泄露:一直占著記憶體不釋放,直到執行結束;嚴格的說這個不算記憶體泄露,因為最終釋放掉了,但是如果執行時間特別長,也可能會導致記憶體耗盡,
導致記憶體泄漏的常見原因
-
回圈過多或死回圈,產生大量物件;
-
靜態集合類引起記憶體泄漏,因為靜態集合的生命周期和 JVM 一致,所以靜態集合參考的物件不能被釋放;下面這個例子中,list 是靜態的,只要 JVM 不停,那么 obj 也一直不會釋放,
public class OOM {
static List list = new ArrayList();
public void oomTests(){
Object obj = new Object();
list.add(obj);
}
}
-
單例模式,和靜態集合導致記憶體泄露的原因類似,因為單例的靜態特性,它的生命周期和 JVM 的生命周期一樣長,所以如果單例物件如果持有外部物件的參考,那么這個外部物件也不會被回收,那么就會造成記憶體泄漏,
-
資料連接、IO、Socket連接等等,它們必須顯示釋放(用代碼 close 掉),否則不會被 GC 回收,
try {
Connection conn = null;
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("url","", "");
Statement stmt = conn.createStatement() ;
ResultSet rs = stmt.executeQuery("....") ;
} catch (Exception e) {
//例外日志
} finally {
//1.關閉結果集 Statement
//2.關閉宣告的物件 ResultSet
//3.關閉連接 Connection
}
-
內部類的物件被長期持有,那么內部類物件所屬的外部類物件也不會被回收,
-
Hash 值發生改變,比如下面中的這個類,它的 hashCode 會隨著變數 x 的變化而變化:
public class ChangeHashCode {
private int x ;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ChangeHashCode other = (ChangeHashCode) obj;
if (x != other.x)
return false;
return true;
}
//省略 set 、get 方法
}
public class HashSetTests {
public static void main(String[] args){
HashSet<ChangeHashCode> hs = new HashSet<ChangeHashCode>();
ChangeHashCode cc = new ChangeHashCode();
cc.setX(10);//hashCode = 41
hs.add(cc);
cc.setX(20);//hashCode = 51
System.out.println("hs.remove = " + hs.remove(cc));//false
hs.add(cc);
System.out.println("hs.size = " + hs.size());//size = 2
}
}
可以看到,在測驗方法中,當元素的 hashCode 發生改變之后,就再也找不到改變之前的那個元素了;
這也是 String 為什么被設定成了不可變型別,我們可以放心地把 String 存入 HashSet,或者把 String 當做 HashMap 的 key 值;
當我們想把自己定義的類保存到散串列的時候,需要保證物件的 hashCode 不可變,
- 記憶體中加載資料量過大;之前專案在一次上線的時候,應用啟動奇慢直到夯死,就是因為代碼中會加載一個表中的資料到快取(記憶體)中,測驗環境只有幾百條資料,但是生產環境有幾百萬的資料,
最后
最新2020整理收集的一線互聯網公司面試真題(都整理成檔案),有很多干貨,包含netty,spring,執行緒,spring cloud等詳細講解,也有詳細的學習規劃圖,面試題整理等,我感覺在面試這塊講的非常清楚:獲取面試資料只需:點擊這里領取!!!暗號:CSDN
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/226844.html
標籤:java
