OOM
1, OutOfMemoryError異常
除了程式計數器外,虛擬機器記憶體的其他幾個執行時區域都有發生OutOfMemoryError(OOM)異常的可能,
Java Heap 溢位
一般的異常資訊:java.lang.OutOfMemoryError:Java heap spacess
java堆用於儲存物件例項,我們只要不斷的建立物件,並且保證GC Roots到物件之間有可達路徑來避免垃圾回收機制清除這些物件,就會在物件數量達到最大堆容量限制後產生記憶體溢位異常。
出現這種異常,一般手段是先通過記憶體映像分析工具(如Eclipse Memory Analyzer)對dump出來的堆轉存快照進行分析,重點是確認記憶體中的物件是否是必要的,先分清是因為記憶體洩漏(Memory Leak)還是記憶體溢位(Memory Overflow)。
如果是記憶體洩漏,可進一步通過工具檢視洩漏物件到GC Roots的引用鏈。於是就能找到洩漏物件時通過怎樣的路徑與GC Roots相關聯並導致垃圾收集器無法自動回收。
如果不存在洩漏,那就應該檢查虛擬機器的引數(-Xmx與-Xms)的設定是否適當。
2, 虛擬機器棧和本地方法棧溢位
如果執行緒請求的棧深度大於虛擬機器所允許的最大深度,將丟擲StackOverflowError異常。
如果虛擬機器在擴充套件棧時無法申請到足夠的記憶體空間,則丟擲OutOfMemoryError異常
這裡需要注意當棧的大小越大可分配的執行緒數就越少。
3, 執行時常量池溢位
異常資訊:java.lang.OutOfMemoryError:PermGen space
如果要向執行時常量池中新增內容,最簡單的做法就是使用String.intern()這個Native方法。該方法的作用是:如果池中已經包含一個等於此String的字串,則返回代表池中這個字串的String物件;否則,將此String物件包含的字串新增到常量池中,並且返回此String物件的引用。由於常量池分配在方法區內,我們可以通過-XX:PermSize和-XX:MaxPermSize限制方法區的大小,從而間接限制其中常量池的容量。
4, 方法區溢位
方法區用於存放Class的相關資訊,如類名、訪問修飾符、常量池、欄位描述、方法描述等。
異常資訊:java.lang.OutOfMemoryError:PermGen space
二。解決辦法
一,主動釋放Bitmap的記憶體
這種方式我簡單說一下,不太推薦,這也是我最開始使用的一種方法,但最後證明它不是最好的。(不推薦)
它的本質思路是:
1、只載入可見區域的Bitmap
2、滑動時不載入
3、停止滑動(Idle)後,開始重新載入可見區域的圖片
4、釋放滑出可見區域的Bitmap的內在。
它比較複雜:
1、我們需要監聽GridView/ListView的滑動事件,這個很簡單做到,AbsListView#setOnScrollListener(OnScrollListener l)
2、主動呼叫Bitmap#recycle()方法,它會導致一個問題,必須判斷這個Bitmap是否被一個View(ImageView等)所引用,如果被引用,我們不能簡單地呼叫recycle()方法,這樣會導致異常,說是View使用了一個已經被回收的Bitmap。
3,我們必須設計自己的執行緒來控制開始/暫停等,因為GridView/ListView的滑動狀態可能不斷地變化,也就是說滑動->停止->滑動,這種狀態可能不斷變化,這樣就會導致我們的執行緒中的run()方法裡面的邏輯比較複雜,一旦複雜,問題就可能就得更多。
基於以上幾點,這種方式不是最好的,所以不推薦。
二,設計Cache
這種方式,我覺得是比較好的一種,它首先利用了cache,我認為cache是一個很重要的東西,把Bitmap的記憶體單獨放在一個地方來管理,這個地方就是cache,它的容量是一定的,我們可能會不斷的向這個cache中新增元素,也可能不斷的移除元素。
為了更好的說明這種方式,先要介紹一下LruCache。
LruCache
1、這其實就是一個LinkedHashMap,任意時刻,當一個值被訪問時,它就會被移動到佇列的開始位置,所以這也是為什麼要用LinkedHashMap的原因,因為要頻繁的做移動操作,為了提高效能,所以要用LinkedHashMap。當cache滿了時,此時再向cache裡面新增一個值,那麼,在佇列最後的值就會從佇列裡面移除,這個值就有可能被GC回收掉。
2、如果我們想主動釋放記憶體,也是可以的,我們可以重寫entryRemoved(Boolean, K, V, V)方法。
3、這個類是執行緒安全的,在多執行緒下面使用這個類,沒不會存在問題。
- synchronized (cache) {
- if (cache.get(key) == null) {
- cache.put(key, value);
- }}
4、LruCache的APILevel是12,也就是說,我們在SDK 2.3.x以下是無法使用的,但是沒關係,LruCache的原始碼不算複雜,我們可以直接把它拷貝到自己的工程目錄就可以了。
AsyncTask<>
這個類也是一個很重要也很常用的類。它封裝了Thread和Handler,我們使用就更加方便,不用關注Handler,我們知道,在後臺執行緒中是不能更新UI,而很多情況下,我們在後臺執行緒做完一件事情後,一般都會更新UI,一般的做法是向關聯到UI執行緒的Handler傳送一個message,在Handler裡面去處理這個message,從而更新UI。用了AsyncTask之後,我們就不用關注Handler了。這個類有幾個重要的方法:
1、onPreExecute(): 在UI執行緒裡面呼叫,它在這個task執行後會立即呼叫。我們在這個方法裡面通常是用於建立一個任務,比如顯示一個等待對話方塊來通知使用者。
2、doInBackground(Params...):這個方法從名字就可以看出,它是執行在後臺執行緒的,在這個方法裡面,去做耗時的事情,比如下載訪問網路,操作檔案等。這這個方法裡面,我們可以呼叫publishProgress(Progress...)來呼叫當前任務的進度,呼叫了這個方法後,對應的onProgressUpdate(Progress...)方法會被呼叫,這個方法是執行在UI執行緒的。
3、onProgressUpdate(Progress...):執行在UI執行緒,在呼叫publishProgress()方法之後。這個方法用來在UI上顯示任何形式的進度,比如你可以顯示一個等待對話方塊,也可以顯示一個文字形式的log,還可以顯示toast對話方塊。
4、onPostExecute(Result):當task結束後呼叫,它執行在UI執行緒。
5、取消一個task,我們可以在任何時候呼叫cancel(Boolean)來取消一個任務,當呼叫了cancel()方法後,onCancelled(Object)方法就會被呼叫,onPostExecute(Object)方法不會被呼叫,在doInBackground(Object[])方法中,我們可以用isCancelled()方法來檢查任務是否取消。
6、幾點規則
- AsyncTask例項必須在UI執行緒中建立
- execute(Params...)方法必須在UI執行緒中呼叫。
- 不用手動呼叫onPreExecute(), onPostExecute(), doInBackground(), onProgressUpdate()方法。
- 一個任務只能被執行一次。
相關文章
- oom killerOOM
- OOM(Out Of Memory)OOM
- inmemory OOM了OOM
- OOM--OUT OF MEMORYOOM
- AIX OOM問題AIOOM
- Linux OOM 機制LinuxOOM
- tikv oom排查過程OOM
- hive job oom問題HiveOOM
- 原來OOM的罪魁禍首是C程式碼---android out of memory(OOM)OOMC程式Android
- OOM分析之問題一)OOM
- Trino Master OOM 排查記錄ASTOOM
- 使用JVisualVM分析OOMLVMOOM
- 深入理解JVM之OOMJVMOOM
- 如何防止 Elasticsearch 服務 OOM ?ElasticsearchOOM
- OOM(Out Of Memory)是什麼?OOM
- IgniteFAQ-9-DataRegion OOMOOM
- iOS開發實踐-OOM治理iOSOOM
- CentOS 配置OOM監控報警CentOSOOM
- OOM分析之問題定位(二)OOM
- OOM的起點到終點OOM
- JVM讀書筆記之OOMJVM筆記OOM
- idea啟動專案oomIdeaOOM
- 執行緒池OOM異常執行緒OOM
- OOM問題解決實踐OOM
- [jvm]常見的oom異常JVMOOM
- Linux 的 OOM 終結者LinuxOOM
- 突發:當機崩潰OOMOOM
- OOM異常型別總結OOM型別
- Kubernetes Pod OOM 排查日記OOM
- 記一次oom問題排查OOM
- jmeter.bat配置(主要關於OOM)JMeterBATOOM
- 使用Netty模擬發生OOMNettyOOM
- Spark —— Spark OOM Error問題排查定位SparkOOMError
- 一次線上OOM問題分析OOM
- MySQL OOM問題處理一則MySqlOOM
- IgniteFAQ-12-Ignite報OOmOOM
- 【爬坑】一次OOM爬坑之旅OOM
- JVM-記憶體區域與OOMJVM記憶體OOM