2009-12-22 30 views
29

我有幾個關於位圖對象和內存及其一般分類的問題。Android中的位圖

  1. 什麼是內存中或本地位圖?
  2. 位圖內存與堆內存有什麼不同?

回答

33

支持Bitmap對象的內存是使用本機代碼(malloc())分配的,而不是關鍵字Java new。這意味着內存由操作系統直接管理,而不是由Dalvik管理。

本地堆和Dalvik堆之間唯一真正的區別是Dalvik的堆是垃圾回收,而本機堆不是。

儘管如此,這裏沒有太大的區別。當你的Bitmap對象被垃圾收集時,它的析構函數會回收本地堆中相關的內存。

來源:

+0

你知道這個bug是否曾經修復?我目前在雷電螺栓上遇到同樣的問題。我正在回收位圖,但他們從未清除本地堆中的任何空間導致oom錯誤。 – 2011-04-15 02:34:01

+5

爲了清楚起見,上述答案對於Android 2.x及以下版本是正確的。從Android 3開始,位圖實例再次成爲堆。這可以很容易地檢查:在android 2.x中創建位圖會使Java堆大小几乎不變,在Adnroid 3.x中創建它將爲Java堆增加大量字節。 – 2012-02-13 12:14:40

+0

啊!所以你說計數現在更直觀了?這真是太棒了 - 除了我們所有編寫hacky代碼的Android堆與本地堆... – 2012-02-24 23:08:08

32

這裏有一個重要的細微之處:雖然位圖的像素在本地堆中分配,在Dalvik的原因一些特別的技巧它將被計入Java堆中。這是因爲兩個原因:

(1)控制應用程序分配的內存量。沒有會計覈算,應用程序可能會分配大量內存(因爲Bitmap對象本身非常小,可以保留任意大量的本機內存),擴展超過了16MB或24MB堆的限制。

(2)幫助確定何時進行GC。如果沒有會計,你可以分配和釋放所說的100個位圖對象的引用; GC不會運行,因爲這些對象很小,但它們實際上可以代表大量的兆字節的實際分配,它們現在沒有及時被GCed。通過對Java堆計算這些分配,垃圾收集器將按照它認爲正在使用的內存運行。

請注意,在很多方面,這是一個實現細節;它很可能會在未來發生變化,儘管這些基本行爲仍然會以某種形式存在,因爲這些都是管理位圖分配的重要特徵。

+1

即使在計算針對java堆的位圖的手機上,本機malloc也可以分配WAY超過16個MiB。 – 2011-02-18 05:44:02

+10

第一條評論是錯誤的,所有手機都按照Dalvik堆限制計數位圖分配。需要注意的主要變化是,從Android 3.0開始,分配實際上是在Dalvik堆中完成的,因此您不再需要處理GC不會像應該那樣積極運行的情況。 – hackbod 2011-05-09 17:17:42

+2

你說得對。儘管如此,GC在處理回收位圖時卻遲遲不能實現。我發現了不可預測的行爲,除非我在回收位圖後手動運行GC(包括下一個「加載」返回再循環位圖的副本,而不是實際從磁盤加載它的趨勢) – 2012-02-24 23:04:59

12

從在野外部署中,我發現了以下設備:

  • 設備,限制對Java堆的16 MIB(位圖幾乎是無限的)。
  • 設備限制爲16 MIB(Java堆+天然位圖存儲)
  • 設備限制到Java堆24 MIB(位圖是幾乎無限制)。
  • 設備限制爲24 MIB(Java堆+天然位圖存儲)

24 MIB往往是高分辨率設備,並且可以與調用Runtime.getRuntime()來檢測maxMemory。()。現在還有32MiB設備,一些根植電話默認爲64MiB。以前,我多次困惑自己試圖弄清楚發生了什麼。我認爲所有設備都將位圖計入堆限制中。但是對android機隊進行任何廣泛的概括是非常困難的。

這是一個非常討厭的問題在Android上,很混亂。這種限制及其行爲記錄不完整,複雜且非常不直觀。它們也因設備和操作系統版本而異,並且有幾個已知的錯誤。部分問題是限制不準確 - 由於堆碎片,你會在實際限制之前打出OOM,並且必須保守地留下一兩個緩衝區。更糟糕的是,我有幾個設備出現了原生段錯誤(100%是Android本身的錯誤),在得到java OOM異常之前就發生了這種錯誤,因此永遠達不到極限是非常重要的,因爲您甚至無法捕獲本機崩潰。有關我的調查的更多詳情,請查看this post。在同一篇文章中,我解釋瞭如何根據限制來衡量使用情況並避免崩潰。

java堆的大小是Runtime.getRuntime()。totalMemory()。

有沒有簡單的方法來測量本地位圖存儲的大小。可以使用Debug.getNativeHeapAllocatedSize()來測量整個本機堆,但只有位圖計入極限(我認爲)。

+0

因爲任何人都可以發佈他們自己的Android版本,所以似乎很可信的是,那裏可能有版本實現了限制堆內存的不同策略,包括上面描述的那些。例如,CyanogenMod允許用戶自己設置堆的限制,所以我不明白爲什麼沒有實現有關您描述的限制的策略的操作系統版本。我很想知道這方面是否有任何官方指導方針。如果沒有,那麼我們就會受到這些操作系統變種的突發事件的影響。 – Carl 2012-02-24 21:49:48

+0

@Carl。據我所知,這是純粹的混亂。儘管一般情況下,mods和rooted手機傾向於增加堆棧限制,通常爲64M。如此嚴重限制Java堆大小的決定是腦死亡遲鈍,並導致可怕的用戶體驗。 – 2012-02-24 22:53:18

+0

它確實迫使我們作爲開發人員認真研究我們對內存的使用。我目前正在開發一個應用程序,它有一個非常大的數據集*必須*完全駐留在堆上(因爲密集的搜索過程),而且我最初的基於字符串數組的實現佔用了15 MB的堆,數組中的每個字符串引用都需要32個字節的數據)。在幾乎達到目前許多設備所強加的24 MB限制之後,我設計了一個只需3.5MB即可保存完全相同信息的自定義數據結構。現在我的應用程序甚至可以在16MB限制的設備上運行。 – Carl 2012-03-12 07:33:39

-1

我們可以通過在清單文件中使用android:largeheap="true"來增加堆大小。這將解決你的一些問題。

+0

想想你的用戶電池......要求大堆來彌補內存分配上的一些錯誤,顯然不能成爲解決方案。 – JuSchz 2014-04-16 12:34:37