【Android常見問題】關於內存泄漏(一)

Android開發過程中,因爲開發的不規範,數據處理的不當方式,常常會造成內存泄漏。內存泄漏,可以用一句話來概括,該釋放的對象未釋放。

在Java方面探討:Java語言是有垃圾回收機制的,理論上是沒有泄漏的,但事實上有些情況下,Java的垃圾回收機制是無法做到垃圾回收的,例如:我們使用完一個對象後,並且不再使用,但是仍然保留着對這對象的引用,那麼垃圾回收器就無法去回收這對象,造成不必要的內存泄漏。相比於C語言不同,C語言本身沒有垃圾回收機制,需要程序員自己去編寫操作內存。先來了解下Java GC(Garbage Collection)垃圾回收機制,簡單的來說,垃圾回收機制對JVM(Java Virtual Machine)中的內存做處理,判斷哪些內存需要被回收,然後根據一定策略去釋放被佔有的內存,保證JVM內存的足夠空間。
垃圾回收機制會做三件事:
- 判斷哪些內存需要回收
- 什麼時候開始回收
- 怎麼去回收內存
理解垃圾回收機制需要知道的幾點:
- 內存是怎麼分配的?
參照下大神的圖
堆區:在垃圾回收機制中,堆區是垃圾垃圾回收機制中最大的管理內存的區域,堆區由所有線程共享。堆區的存在是爲了存儲對象實例,理論上說,所有的對象都在堆區上分配內存。
方法區(Method Area)(引用下別人的總結):在Java虛擬機規範中,將方法區作爲堆的一個邏輯部分來對待,但事實 上,方法區並不是堆(Non-Heap);另外,不少人的博客中,將Java GC的分代收集機制分爲3個代:青年代,老年代,永久代,這些作者將方法區定義爲“永久代”,這是因爲,對於之前的HotSpot Java虛擬機的實現方式中,將分代收集的思想擴展到了方法區,並將方法區設計成了永久代。不過,除HotSpot之外的多數虛擬機,並不將方法區當做永 久代,HotSpot本身,也計劃取消永久代。本文中,由於筆者主要使用Oracle JDK6.0,因此仍將使用永久代一詞。方法區是各個線程共享的區域,用於存儲已經被虛擬機加載的類信息(即加載類時需要加載的信息,包括版本、field、方法、接口等信息)、final常量、靜態變量、編譯器即時編譯的代碼等。方法區在物理上也不需要是連續的,可以選擇固定大小或可擴展大小,並且方法區比堆還多了一個限制:可以選擇是否執行垃圾收集。一般的,方法區上 執行的垃圾收集是很少的,這也是方法區被稱爲永久代的原因之一(HotSpot),但這也不代表着在方法區上完全沒有垃圾收集,其上的垃圾收集主要是針對 常量池的內存回收和對已加載類的卸載。
程序計數器:程序計數器是個非常小的內存區域,通常只用來標記程序運行到哪行代碼,字節碼解釋器在工作時,會通過改變這個計數器的值來取下一條語句指令。
虛擬機棧:線程內的每個方法在運行的同時,都會創建一個棧幀。棧幀中存儲的有:
1. 局部變量表
2. 操作站
3. 動態鏈接
4. 方法出口
方法被調用時,棧幀在JVM棧中入棧,當方法執行完成時,棧幀出棧。
局部變量表中存儲着方法的相關局部變量,包括數據類型,對象引用,返回地址。
虛擬機棧中定義了兩中異常:
1.棧溢出:線程調用的棧深度大於虛擬機允許的棧深度。
2.內存溢出:多數JVM都允許動態擴展虛擬機棧的大小(有少部分是固定長度的),所以線程可以一直申請棧,直到內存不足。
本地方法棧:類似於虛擬機棧,唯一的區別是:虛擬機棧是執行Java方法的,而本地方法棧是用來運行native方法的。

Java內存分配機制
Java內存分配機制:分代分配,然後分代回收。
對象根據對象的存活時間被分爲:年輕代,年老代,永久代。
1.年輕代:對象被創建時,內存的分配通常發生在年輕代,大多數對象在創建後很快就基本不再使用了,於是被年輕代的垃圾回收機制回收了。關於年輕代:分爲三個區域,一個Eden區,兩個存活區。同時年輕代方面遵守以下幾條:1.絕大多數會創建在Eden區,其中大多數對象會很快消亡,Eden區是連續的內存空間,所以在分配內存上速度極快。2.當Eden區存滿時,將消亡的對象清理掉,並將剩餘的對象複製到一個存活區0。3當存活區0也滿時,將存活的對象直接複製到存活區1。總的來說:Eden區是連續空間,而存活區總有一個保持爲空。

發佈了70 篇原創文章 · 獲贊 196 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章