- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- Java基礎之內存泄漏與溢出詳解
內存泄露( memory leak):是指程序在申請內存后,無(wú)法釋放已申請的內存空間,多次內存泄露堆積后果很?chē)乐?,內存遲早會(huì )被占光。內存泄漏最終會(huì )造成內存溢出。
內存溢出(out of memory) :是指程序在申請內存時(shí),沒(méi)有足夠的內存空間供其使用
JVM中有一下幾種內存空間:
Java的內存回收機制:
Java堆是一個(gè)運行時(shí)數據區,類(lèi)的實(shí)例(對象)從中分配空間,JVM堆中儲存著(zhù)正在運行的應用程序所建立的所有對象,“垃圾回收”主要也是和堆有關(guān)。
不論哪種語(yǔ)言的內存分配方式,都需要返回所分配內存的真實(shí)地址,也就是返回一個(gè)指針到內存塊的首地址,Java中對象是采用new或者反射的方法創(chuàng )建的,這些對象的創(chuàng )建都是在堆(Heap)中分配的。
內存泄露是指當前未被引用的對象持續占用內存導致內存空間的浪費。常見(jiàn)的內存泄漏有以下幾大類(lèi):
(1)靜態(tài)集合類(lèi)引起
比如說(shuō)靜態(tài)HashMap、Vector等,這些靜態(tài)變量的生命周期和應用程序一致,他們所引用的所有的對象Object也不能被釋放。
Static Vector v = new Vector(10); for (int i = 1; i<100; i++) { Object o = new Object(); v.add(o); o = null; }//
如上所示,循環(huán)申請Object 對象,并將所申請的對象放入一個(gè)Vector 中,如果僅僅釋放引用本身(o=null),那么Vector 仍然引用該對象,所以這個(gè)對象對GC 來(lái)說(shuō)是不可回收的。
必須要降Vector對象設置為null,才能回收這部分占用的內存
(2)當集合里面的對象屬性被修改后,再調用remove()方法時(shí)不起作用。
主要原因是:set類(lèi)存儲對象是通過(guò)hashcode存儲,如對象屬性被修改,remove方法就不能通過(guò)原先的hashcode刪除對象。
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()+" 個(gè)元素!"); //結果:總共有:3 個(gè)元素! p3.setAge(2); //修改p3的年齡,此時(shí)p3元素對應的hashcode值發(fā)生改變,remove是通過(guò)hashcode刪除對象 set.remove(p3); //此時(shí)remove不掉,造成內存泄漏 set.add(p3); //重新添加,居然添加成功 System.out.println("總共有:"+set.size()+" 個(gè)元素!"); //結果:總共有:4 個(gè)元素! for (Person person : set) { System.out.println(person); } }
(3)監聽(tīng)器
監聽(tīng)器調用太多,釋放對象時(shí)未刪除監聽(tīng)器也可能造成內存泄漏
(4)各種連接
數據庫連接(dataSourse.getConnection()),網(wǎng)絡(luò )連接(socket)和io連接,除非其顯式的調用了其close()方法將其連接關(guān)閉,否則是不會(huì )自動(dòng)被GC 回收的。Connection一旦回收,Resultset 和Statement 對象就會(huì )立即為NULL
如果使用連接池,Resultset 和Statement 對象也需要顯式的關(guān)閉,否則就會(huì )造成大量的Statement 對象無(wú)法釋放,從而引起內存泄漏,這種情況下一般都會(huì )在try里面去的連接,在finally里面釋放連接。
(5)單例模式
如果單例對象持有外部對象的引用,那么這個(gè)外部對象將不能被jvm正?;厥?,就會(huì )導致內存泄露。
比如說(shuō):
class A{ public A(){ B.getInstance().setA(this); } .... } //B類(lèi)采用單例模式 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模式,它持有一個(gè)A對象的引用,而這個(gè)A類(lèi)的對象將不能被回收
當內存占有量超過(guò)了虛擬機的分配的最大值時(shí)就會(huì )產(chǎn)生內存溢出(JVM里面分配不出更多的page)
一般出現情況:
JVM內存模型:
Java應用程序在啟動(dòng)時(shí)會(huì )指定所需要的內存大小,它被分割成兩個(gè)不同的區域:Heap space(堆空間)和Permgen(永久代)。
(1)JVM Heap堆溢出:java.lang.OutOfMemoryError: Java heap space
在JVM中如果98%的時(shí)間是用于GC,且可用的Heap size 不足2%的時(shí)候將拋出此異常信息。
JVM啟動(dòng)時(shí)會(huì )自動(dòng)設置JVM Heap的值,可以利用JVM提供的-Xmn -Xms -Xmx等選項可進(jìn)行設置,當需要為對象實(shí)例分配內存,而堆的內存占用又已經(jīng)達到-Xmx設置的最大值。將會(huì )拋出OutOfMemoryError異常。
解決方法:手動(dòng)設置JVM Heap(堆)的大小。
(2)PermGen space溢出: java.lang.OutOfMemoryError: PermGen space
PermGen space的全稱(chēng)是Permanent Generation space,是指內存的永久保存區域。
PermGen space主要是被JVM存放Class和Meta信息的,Class在被Load的時(shí)候被放入PermGen space區域,它和存放Instance的Heap區域不同,sun的 GC不會(huì )在主程序運行期對PermGen space進(jìn)行清理,所以如果你的APP會(huì )載入很多CLASS的話(huà),就很可能出現PermGen space溢出。一般發(fā)生在程序的啟動(dòng)階段
解決方法: 通過(guò)-XX:PermSize和-XX:MaxPermSize設置永久代大小即可。
(3)棧溢出: java.lang.StackOverflowError : Thread Stack space
調用構造函數的 “層”太多了,以致于把棧區溢出了。通俗一點(diǎn)講就是單線(xiàn)程的程序需要的內存太大了。 通常遞歸也不要遞歸的層次過(guò)多,很容易溢出。
解決方法:
1:修改程序。
2:通過(guò) -Xss: 來(lái)設置每個(gè)線(xiàn)程的Stack大小即可。
在Java虛擬機規范中,對這個(gè)區域規定了兩種異常狀況:
到此這篇關(guān)于Java基礎之內存泄漏與溢出詳解的文章就介紹到這了,更多相關(guān)Java內存泄漏與溢出內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站