2017年9月30日 星期六

Android get app icon crash if recycle the bitmap

在實做取得 app icon 的時候發現記憶體使用率會飆高而且常常降不下來, 想說可能是 birmap 吃掉記憶體,所以在使用完 bitmap 後就用 recycle 來讓 GC 可以做記憶體回收,但是發現呼叫 recycle 之後再次要取得 app icon 時常常會出現 exception 說使用到已經 recycle 的 bitmap,就在想會不會是系統已經做了 app icon 的 cache,所以每次取到的 app icon 有可能是跟之前一樣的 object,這篇的說法也印證了我的猜想,系統的確會內部自己做 cache

既然不能 recycle bitmap,但記憶體又這麼高,該怎麼辦?這時發現 Android 有提供一個 LruCache 物件來做 cache,很適合 bitmap 使用,試著用用看,結果...在這樣系統跟我都做了 cache 的情況下,記憶體使用率真的變低了

為什麼兩邊都做 cache 反而記憶體會下降,我認為 Android 系統內部的 cache 機制大概有問題 ,既然系統已經內部有做 app icon 的 cache 了,應用程式端就不需要再自己做 cache 才對,cache 的使用效能與記憶體管理系統自己要注意,而不是讓應用程式來煩惱,那還不如你系統就不要做 cache,這樣我記憶體使用率可以再降一點

為了這個問題還去查了一下 PackageManager 的原始碼,才發現 PackageManager 的實作提供者有兩個 ApplicationPackageManager 和 PackageManagerService 這些物件又互相 call 來 call 去對方的 method,看了有點頭昏

恩...繼上次 activity context create PackageManager memory leak 後又一個 Android 的坑 

2017年9月27日 星期三

java blocking IO read 不支援 interrupt

一直以為 java 所有的 blocking operation 是可以用 thread.interrupt() method 中斷的,但是後來才發現  java 原本的 blocking IO library 是不支援 interrupt 的,例如去 read 一個 socket,然後用 thread.interrupt() 去中斷呼叫 read 的 thread,會發現 read 並沒有被中斷

新的 File library 像是 java.nio 才有支援 interrupt,而原本的 IO library 就要考慮其它的方式來中斷一個 blocking read,例如把 socket close,或是去 polling 是否 data available,若 data available 再呼叫 blocking read method

2017年9月17日 星期日

查詢 kernel module CPU 使用率的好幫手 -- Kernrate

最近在調查 CPU 使用率飆高問題的時候,在這邊發現一個好用的工具,kernrate,可以用來查詢 kernel module 的 CPU 使用率

它的用法非常簡單,只有一個執行檔,直接執行後就會開始記錄 CPU 使用率,跑一段時間後用 ctrl-c 就會停止執行並印出它所記錄的 CPU 使用率

不過官網下載的安裝包裝完後只有 x86 跟 IA64 兩種版本的執行檔,沒有 x64 版本,後來網路上發現 windows DDK 中有 x64 版本,所以若是想在 x64 上用的話,就先下載 windows DDK 吧

2017年9月11日 星期一

Activity context leak caused by getPackageManager

最近用 leakcanary 檢查有沒有 memory leak 的時候發現了 context leak,而 leak 的 memory 有 2MB 這麼多

context leak 是 android 最常發生的 memory leak 之一,吃掉的 memory 隨著你的 activity 大小而變,因為你的 activity context 無法釋放,隨著你的 activity 中持有的所有資源都會無法釋放

leakcanary 的強大功能就是會顯示出造成 memory leak 的來龍去脈,照著 leakcanary 的提示,是 UserManager 其中的一個 static variable reference 到我的 activity context,不過我沒有在 activity 中使用到 UserManager,怎麼會讓 context 被 UserManager 持有的

一番查證後,在我的 activity 中有去使用 PackageManager,而 PackageManager 內部使用到了 UserManager,而在 UserManager 第一次被使用到的時候會將自身存在一個 static variable 中,從而讓 context 被這個 static variable hold 住



android framework 用這樣的實作,難怪會有 memory leak,還讓你 leak 的不知不覺,只要用 activity context 呼叫 getPackageManager 就踩到坑裡

這個 memory leak 實際上是 android 5.0 的一個 bug,在 android 7.0 已經修正掉了,app 開發者要避開這個 memory leak 的話,需要用 application context 來呼叫 getPackageManage,而不是用 activity context

開發 android 時真的要小心,注意自己的 code 還不夠,還要注意不要掉到 android 挖好的洞裡

2017年9月7日 星期四

秦九韶演算法

秦九韶演算法是在算一元多項式時非常有用的演算法,每一次迭代運算時只需要一次加法跟乘法,不需要次方運算

以時間複雜度來講,求最高 n 次方的多項式時,用秦九韶演算法需要花費 2n 的時間複雜度,但是以次方運算的時間複雜度為 n 平方,可見節省了相當多的運算次數

演算法筆記中也有介紹

2017年9月2日 星期六

找出給定範圍內的質數 -- Sieve of Eratosthenes

Sieve of Eratosthenes是一種找出給定範圍內的演算法,從該範圍內最小質數開始,逐步刪除該質數的乘積,圖形化表達如下


C 程式如下
bool prime[20000000];

void eratosthenes()
{
    for (int i=0; i < 20000000; i++)
        prime[i] = true;

    prime[0] = false;
    prime[1] = false;

    for (int i=2; i < 20000000; i++)
        if (prime[i])
            for (int j=i*i; j < 20000000; j+=i)
                prime[j] = false;
}
用來實做質數表非常有用,在這邊也有提到更多細節與加速該演算法的方法