Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 如何「偷」Android 的內存?,「偷」android

如何「偷」Android 的內存?,「偷」android

編輯:關於android開發

如何「偷」Android 的內存?,「偷」android


之前在做一個內存優化的時候,使用到了MemoryFile,由此發現了MemoryFile的一些特性以及一個非常trickly的使用方法,因此在這裡記錄一下

What is it

MemoryFile是android在最開始就引入的一套框架,其內部實際上是封裝了android特有的內存共享機制Ashmem匿名共享內存,簡單來說,Ashmem在Android內核中是被注冊成一個特殊的字符設備,Ashmem驅動通過在內核的一個自定義slab緩沖區中初始化一段內存區域,然後通過mmap把申請的內存映射到用戶的進程空間中(通過tmpfs),這樣子就可以在用戶進程中使用這裡申請的內存了,另外,Ashmem的一個特性就是可以在系統內存不足的時候,回收掉被標記為”unpin”的內存,這個後面會講到,另外,MemoryFile也可以通過Binder跨進程調用來讓兩個進程共享一段內存區域。由於整個申請內存的過程並不再Java層上,可以很明顯的看出使用MemoryFile申請的內存實際上是並不會占用Java堆內存的。

MemoryFile暴露出來的用戶接口可以說跟他的名字一樣,基本上跟我們平時的文件的讀寫基本一致,也可以使用InputStream和OutputStream來對其進行讀寫等操作:

    1 2 3 4 MemoryFile memoryFile = new MemoryFile(null, inputStream.available()); memoryFile.allowPurging(false); OutputStream outputStream = memoryFile.getOutputStream(); outputStream.write(1024);

上面可以看到allowPurging這個調用,這個就是之前說的”pin”和”unpin”,在設置了allowPurging為false之後,這個MemoryFile對應的Ashmem就會被標記成”pin”,那麼即使在android系統內存不足的時候,也不會對這段內存進行回收。另外,由於Ashmem默認都是”unpin”的,因此申請的內存在某個時間點內都可能會被回收掉,這個時候是不可以再讀寫了

Tricks

MemoryFile是一個非常trickly的東西,由於並不占用Java堆內存,我們可以將一些對象用MemoryFile來保存起來避免GC,另外,這裡可能android上有個BUG:

在4.4及其以上的系統中,如果在應用中使用了MemoryFile,那麼在dumpsys meminfo的時候,可以看到多了一項Ashmem的值:

可以看出來雖然MemoryFile申請的內存不計入Java堆也不計入Native堆中,但是占用了Ashmem的內存,這個實際上是算入了app當前占用的內存當中

但是在4.4以下的機器中時,使用MemoryFile申請的內存居然是不算入app的內存中的:

而且這裡我也算過,也是不算入Native Heap中的,另外,這個時候去系統設置裡面看進程的內存占用,也可以看出來其實並沒有計入Ashmem的內存的

這個應該是android的一個BUG,但是我搜了一下並沒有搜到對應的issue,搞不好這裡也可能是一個feature

而在大名鼎鼎的Fresco當中,他們也有用到這個bug來避免在decode bitmap的時候,將文件的字節讀到Java堆中,使用了MemoryFile,並利用了這個BUG然這部分內存不算入app中,這裡分別對應了Fresco中的GingerbreadPurgeableDecoder和KitKatPurgeableDecoder,Fresco在decode圖片的時候會在4.4和4.4以下的系統中分別使用這兩個不同的decoder

從這個地方可以看出來,使用MemoryFile,在4.4以下的系統當中,可以幫我們的app額外”偷”一些內存,並且可以不計入app的內存當中

Summary

這裡主要是簡單介紹了MemoryFile的基本原理和用法,並且闡述了一個MemoryFile中一個可以幫助開發者”偷”內存的地方,這個是一個非常trickly的方法,雖然4.4以下使用這塊的內存並不計入進程當中,但是並不推薦大量使用,因為當設置了allowPurging為false的時候,這個對應的Ashmem內存區域是被”pin”了,那麼在android系統內存不足的時候,是不能夠把這段內存區域回收的,如果長時間沒有釋放的話,這樣子相當於無端端占用了大量手機內存而又無法回收,那對系統的穩定性肯定會造成影響

 

問啊-一鍵呼叫程序員答題神器,牛人一對一服務,開發者編程必備官方網站:www.wenaaa.com

QQ群290551701 聚集很多互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved