android之內存洩漏

相信大部分童靴都有聽說個名詞:

內存洩漏 究竟什麼是內存洩漏,它具體有什麼危害呢?且聽我娓娓道來

android之內存洩漏

android之內存洩漏

JVM/ART


首先為大家普及下,java運行時是有一套虛擬機機制存在的:

JVM(Java虛擬機)

是一個虛構出來的運行Java程序的運行時,是通過在實際的計算機上仿真模擬各種計算機功能的實現。它具有完善的硬件架構(如處理器、堆棧、寄存器等),還具有相應的指令系統,使用JVM就是使Java程序支持與操作系統無關。

理論上在任何操作系統中,只要有對應的JVM,即可運行Java程序。

ART(android虛擬機)

是在Android系統上運行Android程序的虛擬機,其指令集是基於寄存器架構的,執行特有的文件格式-dex字節碼來完成對象生命週期管理、堆棧管理、線程管理、安全異常管理、垃圾回收等重要功能。

其實ART就是在JVM基礎上專門為android移動設備定製的一套虛擬機方案。

內存洩漏/內存溢出


內存洩露(Memory leak)

程序在向系統申請分配內存空間後(new),在使用完畢後未釋放。結果導致一直佔據該內存單元,我們和程序都無法再使用該內存單元,直到程序結束,這是內存洩露。

內存溢出(out of memory)

程序向系統申請的內存空間超出了系統能給的,比如一車最多能坐5個人,你卻非要塞下10個,車就擠爆了。

大量的內存洩露會導致內存溢出(oom)

內存區域


JAVA是在JVM所虛擬出的內存環境中運行的,JVM的內存可分為三個區:

堆(heap)、棧(stack)和方法區(method)。

棧(stack)

是簡單的數據結構,但在計算機中使用廣泛。棧最顯著的特徵是:LIFO(Last In, First Out, 後進先出),棧中只存放基本類型和對象的引用(不是對象)

堆(heap)

堆內存用於存放由new創建的對象和數組。在堆中分配的內存,由java虛擬機自動垃圾回收器來管理。JVM只有一個堆區(heap)被所有線程共享,堆中不存放基本類型和對象引用,只存放對象本身。

方法區(method)

又叫靜態區,跟堆一樣,被所有的線程共享。方法區包含所有的class和static變量

內存洩漏原因分析


android之內存洩漏

那麼問題來了?究竟哪部分的內存會導致內存洩漏呢?

在JAVA中JVM的棧記錄了方法的調用,每個線程擁有一個棧。

在線程的運行過程當中,執行到一個新的方法調用,就在棧中增加一個內存單元,即幀(frame)。在frame中,保存有該方法調用的參數、局部變量和返回地址。

然而JAVA中的局部變量只能是基本類型變量(int),或者對象的引用。所以在棧中只存放基本類型變量和對象的引用。引用的對象保存在堆中。

當某方法運行結束時,該方法對應的frame將會從棧中刪除,frame中所有局部變量和參數所佔有的空間也隨之釋放。

線程回到原方法繼續執行,當所有的棧都清空的時候,程序也就隨之運行結束。

而對於堆內存,堆存放著普通變量。在JAVA中堆內存不會隨著方法的結束而清空,所以在方法中定義了局部變量,在方法結束後變量依然存活在堆中。

綜上所述,棧(stack)可以自行清除不用的內存空間。但是如果我們不停的創建新對象,堆(heap)的內存空間就會被消耗盡。

所以JAVA引入了垃圾回收(garbage collection,簡稱GC)去處理堆內存的回收,但如果對象一直被引用無法被回收,造成內存的浪費,無法再被使用。

所以對象無法被GC回收就是造成內存洩露的原因!

垃圾回收機制


垃圾回收(garbage collection,簡稱GC)可以自動清空堆中不再使用的對象。

在JAVA中對象是通過引用使用的。如果再沒有引用指向該對象,那麼該對象就無從處理或調用該對象,這樣的對象稱為不可到達(unreachable)。

垃圾回收用於釋放不可到達的對象所佔據的內存。

根據上圖可以知道:由

於obj4沒有root指向它,所以GC會釋放它obj7由於還有其他引用指向它,所以得不到釋放如果持有對象的強引用,垃圾回收器是無法在內存中回收這個對象。

所以內存洩露的真因是:

持有對象的強引用,且沒有及時釋放,進而造成內存單元一直被佔用,浪費空間,甚至可能造成內存溢出!

內存洩漏對應用的影響


內存洩漏對於app沒有直接危害,即使有發現內存洩漏的情況,也不一定會立即引起app崩潰,但是通過累積效應,應用會爆出各種問題:

  1. 內存得不到釋放,慢慢的會造成app內存溢出,導致崩潰

  2. 內存洩漏同時可能會觸發系統頻繁GC,發生內存抖動,會導致系統性能問題(卡頓不流暢)


分享到:


相關文章: