1. 程式人生 > >JVM記憶體溢位有什麼優化、具體使用場景

JVM記憶體溢位有什麼優化、具體使用場景

一、Java記憶體回收機制               
不論哪種語言的記憶體分配方式,都需要返回所分配記憶體的真實地址,也就是返回一個指標到記憶體塊的首地址。Java中物件是採用new或者反射的方法建立的,這些物件的建立都是在堆(Heap)中分配的,所有物件的回收都是由Java虛擬機器通過垃圾回收機制完成的。GC為了能夠正確釋放物件,會監控每個物件的執行狀況,對他們的申請、引用、被引用、賦值等狀況進行監控,Java會使用有向圖的方法進行管理記憶體,實時監控物件是否可以達到,如果不可到達,則就將其回收,這樣也可以消除引用迴圈的問題。在Java語言中,判斷一個記憶體空間是否符合垃圾收集標準有兩個:一個是給物件賦予了空值null,以後再沒有呼叫過,另一個是給物件賦予了新值,這樣重新分配了記憶體空間

二、Java記憶體洩露引起原因
首先,什麼是記憶體洩露?經常聽人談起記憶體洩露,但要問什麼是記憶體洩露,沒幾個說得清楚。記憶體洩露是指無用物件(不再使用的物件)持續佔有記憶體或無用物件的記憶體得不到及時釋放,從而造成的記憶體空間的浪費稱為記憶體洩露。記憶體洩露有時不嚴重且不易察覺,這樣開發者就不知道存在記憶體洩露,但有時也會很嚴重,會提示你Out of memory
那麼,Java記憶體洩露根本原因是什麼呢?長生命週期的物件持有短生命週期物件的引用就很可能發生記憶體洩露,儘管短生命週期物件已經不再需要,但是因為長生命週期物件持有它的引用而導致不能被回收,這就是java中記憶體洩露的發生場景。具體主要有如下幾大類:
1、靜態集合類引起記憶體洩露:
像HashMap

、Vector等的使用最容易出現記憶體洩露,這些靜態變數的生命週期和應用程式一致,他們所引用的所有的物件Object也不能被釋放,因為他們也將一直被Vector等引用著。
例:

複製程式碼 程式碼如下:


Static Vector v = new Vector(10);
for (int i = 1; i<100; i++)
{
Object o = new Object();
v.add(o);
o = null;
}//

在這個例子中,迴圈申請Object 物件,並將所申請的物件放入一個Vector 中,如果僅僅釋放引用本身(o=null),那麼Vector 仍然引用該物件,所以這個物件對GC 來說是不可回收的。因此,如果物件加入到Vector 後,還必須從Vector 中刪除,最簡單的方法就是將Vector物件設定為null。(解決方案)

2、當集合裡面的物件屬性被修改後,再呼叫remove()方法時不起作用。

例:

複製程式碼 程式碼如下:


public static void main(String[] args)
{
Set<Person> set = new HashSet<Person>();
Person p1 = new Person("
唐僧","pwd1",25);
Person p2 = new Person("孫悟空
","pwd2",26);
Person p3 = new Person("豬八戒
","pwd3",27);
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println("總共有:"+set.size()+" 個元素!"); //結果:總共有:3 個元素
!
p3.setAge(2); //修改p3的年齡,此時p3元素對應的hashcode值發生改變

set.remove(p3);//此時remove不掉,造成記憶體洩漏

set.add(p3);//重新新增,居然新增成功
System.out.println("總共有:"+set.size()+" 個元素!"); //結果:總共有:4 個元素!
for (Person person : set)
{
System.out.println(person);
}
}

3、監聽器
在java 程式設計中,我們都需要和監聽器打交道,通常一個應用當中會用到很多監聽器,我們會呼叫一個控制元件的諸如addXXXListener()等方法來增加監聽器,但往往在釋放物件的時候卻沒有記住去刪除這些監聽器,從而增加了記憶體洩漏的機會。

4、各種連線
比如資料庫連線(dataSourse.getConnection()),網路連線(socket)和io連線,除非其顯式的呼叫了其close()方法將其連線關閉,否則是不會自動被GC 回收的。對於Resultset 和Statement 物件可以不進行顯式回收,但Connection 一定要顯式回收,因為Connection 在任何時候都無法自動回收,而Connection一旦回收,Resultset 和Statement 物件就會立即為NULL。但是如果使用連線池,情況就不一樣了,除了要顯式地關閉連線,還必須顯式地關閉Resultset Statement 物件(關閉其中一個,另外一個也會關閉),否則就會造成大量的Statement 物件無法釋放,從而引起記憶體洩漏。這種情況下一般都會在try裡面去的連線,在finally裡面釋放連線。

5、內部類和外部模組等的引用
內部類的引用是比較容易遺忘的一種,而且一旦沒釋放可能導致一系列的後繼類物件沒有釋放。此外程式設計師還要小心外部模組不經意的引用,例如程式設計師A 負責A 模組,呼叫了B 模組的一個方法如:
public void registerMsg(Object b);
這種呼叫就要非常小心了,傳入了一個物件,很可能模組B就保持了對該物件的引用,這時候就需要注意模組B 是否提供相應的操作去除引用。

6、單例模式
不正確使用單例模式是引起記憶體洩露的一個常見問題,單例物件在被初始化後將在JVM的整個生命週期中存在(以靜態變數的方式),如果單例物件持有外部物件的引用,那麼這個外部物件將不能被jvm正常回收,導致記憶體洩露,考慮下面的例子:

複製程式碼 程式碼如下:


class A{
public A(){
B.getInstance().setA(this);
}
....
}
//B
類採用單例模式
class B{
private A a;
private static B instance=new B();
public B(){}
public static B getInstance(){
return instance;
}
public void setA(A a){
this.a=a;
}
//getter...
}

顯然B採用singleton模式,它持有一個A物件的引用,而這個A類的物件將不能被回收。想象下如果A是個比較複雜的物件或者集合型別會發生什麼情況

相關推薦

JVM記憶體溢位什麼優化具體使用場景

一、Java記憶體回收機制               不論哪種語言的記憶體分配方式,都需要返回所分配記憶體的真實地址,也就是返回一個指標到記憶體塊的首地址。Java中物件是採用new或者反射的方法建

jvm 記憶體溢位的多種原因及優化方法

讓我們看一下我們日常在開發過程中接觸記憶體溢位的異常:   Exception in thread "main" [Full GCjava.lang.OutOfMemoryError: Java heap space at java.util.Ar

Hadoop記憶體溢位(OOM)分類引數調優化(程式碼模擬記憶體溢位型別並分析原因)

從Java GC的角度解讀代碼:程式20行new的Person物件會首先會進入年輕代的Eden中(如果對象太大可能直接進入年老代)。在GC之前對象是存在Eden和from中的,進行GC的時候Eden中的對象被拷貝到To這樣一個survive空間(survive(倖存)空間:包括from和to,他們的空間大小是

JVM 記憶體溢位追蹤調優與 記憶體溢位溢位原因

出處1:http://www.iteye.com寫java程式時大家一定對一下兩條異常並不陌生: java.lang.OutOfMemoryError: Java heap space java.lang.OutOfMemoryError: PermGen space 尤其當

JVM記憶體中的堆疊方法區

堆疊、堆、方法區 JAVA的JVM的記憶體可分為3個區:堆(heap)、堆疊(stack)和方法區(method) 堆區:(例如:存放成員變數,又稱例項變數) 提供所有類例項和陣列物件儲存區域。 jvm只有一個堆區(heap)被所有執行緒共享,堆中不存放基本型別和物件引用,只

JVM——記憶體溢位記憶體洩漏的區別

今日本帥博主在研究JVM,今天我們就來遊走於記憶體溢位與記憶體洩漏之間,且看看它們是個啥,且又有啥子區別。 1.記憶體溢位和記憶體洩漏是啥 記憶體溢位 out of memory,是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現out of memory;比如申請了一個int

JVM 記憶體初學 (堆(heap)棧(stack)和方法區(method) )

先了解具體的概念: JAVA的JVM的記憶體可分為3個區:堆(heap)、棧(stack)和方法區(method) 堆區: 1.儲存的全部是物件,每個物件都包含一個與之對應的class的資訊。(class的目的是得到操作指令) 2.jvm只有一個堆區(heap)被所有執行緒

生產環境jvm記憶體溢位問題處理OutOfMemoryError

生產環境jvm記憶體溢位問題處理OutOfMemoryError 問題描述 服務正常部署執行後,前端介面偶爾出現請求無響應情況,頁面出現持續性卡頓。伺服器日誌報下面這個異常: Exception: java.lang.OutOfMemoryError thrown

Spark任務提交 yarn-cluster模式 解決jvm記憶體溢位問題 以及簡單概述jdk7方法區和jdk8元空間

yarn-cluster 提價任務流程 1、提交方式 ./spark-submit --master yarn --deploy-mode cluster --class org.apache.spark.examples.SparkPi ../lib/spark-exampl

死磕JVM-如何構造JVM記憶體溢位和棧溢位

為什麼要寫這個題目?我記得我在面試阿里的時候面試官問了我這個問題,當時沒能答得很好,只說了些概念的東西,很是心虛,於是下定決心要把這個問題搞懂,現在終於把這個問題懟清楚了,分享給大家,希望你們以後面試問到這種問題能有所準備。 Java虛擬機器中描述了兩種異常: 1、如果執

Tomcat中JVM記憶體溢位及合理配置

Tomcat本身不能直接在計算機上執行,需要依賴於硬體基礎之上的作業系統和一個Java虛擬機器。Tomcat的記憶體溢位本質就是JVM記憶體溢位,所以在本文開始時,應該先對Java JVM有關記憶體方面的知識進行詳細介紹。 一、Java JVM記憶體介紹 JVM管理兩種

分享一次解決線上java應用導致JVM記憶體溢位(OOM)的問題

某個線上的應用執行幾天後,總是出現卡死甚至出現OOM的情況。 注:文中圖片可能與描述不符,僅作為演示! 通過Linux的top命令檢視cpu佔比 首先通過top命令檢視,發現某個java程式佔用了較高記憶體: JDK的jps命令確定是哪個j

JVM記憶體溢位詳解(棧溢位,堆溢位,持久代溢位以及無法建立本地執行緒)

寫在前面 記憶體溢位和記憶體洩漏的區別: 記憶體溢位 out of memory,是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是記

Jvm記憶體溢位的幾種情況

1、java堆溢位 java對用於儲存物件的例項,只要不斷的建立物件,並且保證GC Roots到物件之間有可達路徑來避免垃圾回收機制清除這些物件,那麼在物件數量達到最大堆的容量限制之後機會產生記憶體溢

定位JVM記憶體溢位問題思路總結

JVM的記憶體溢位問題,是個常見而有時候有非常難以定位的問題。定位記憶體溢位問題常見方法有很多,但是其實很多情況下可供你選擇的有效手段非常有限。很多方法在一些實際場景下沒有實用價值。這裡總結下我的一些定位思路。 要定位JVM記憶體溢位問題,首先要對JVM的記憶體佈局有一定

java JVM 記憶體溢位 64位JDK

新產品釋出,拿來試用。由於本機是win7_x64,但是為方便工作,機器安裝了從32位的JDK1.5一直到64位的JDK1.6的4個JDK。為保證執行時能與大多數人的執行狀況相同,依然採用了32位的jdk1.6來執行產品。 結果,我第一次碰到應用伺服器剛起來就crash的

Android記憶體溢位優化(四)——防止Handler導致的記憶體洩露

在Android中,子執行緒不能直接更新主執行緒的UI,因此提供了Handler來方便我們操作。在子執行緒呼叫handler可以直接傳送Message加入MessageQueue,Looper取出

常見jvm記憶體溢位典型案例

-agentlib:hprof=heap=dump,format=b,file=C:\Users\sxp\Desktop\heapDump1.hprof jvm生成快照檔案 1吞吐量優先收集器在硬體提升的情況下由於大物件在更大堆中的頻繁

JVM解讀(四):JVM記憶體溢位異常分析

JVM全稱是java Virtual Machine(java虛擬機器),JVM遮蔽了與各個計算機平臺相關的軟體和硬體差異。 在接下來的日子裡,通過寫部落格的形式學習JVM,讓自己更懂得Java! 本系列文章是對《深入分析javaweb技術內幕》和《深入理解

JVM記憶體溢位與排錯

JVM記憶體溢位與排錯 一、JVM堆記憶體溢位 Java堆用於儲存物件例項,我們只要不斷建立物件,並且保證GC Roots到物件之間有可達路徑來避免垃圾回收機制來清除這些物件,就會在物件數量達到最大隊的容量限制後產生記憶體溢位異常。 程式碼: /** * Java堆記憶體