編輯:關於android開發
在實際的Android開發過程中,我們遇到了一些奇奇怪怪的Crash,通過sigaction再配合libcorkscrew以及一些第三方的Crash Reporter都捕獲不到發生Crash的具體信息,十分頭疼。然後我們通過Bugly上報的Java的CallStack觀察發現這些Crash發現了一些共同的信息:
看來是和OpenGL有關系,於是我們進一步對程序輸出的log進行觀察,又發現:
從這個log裡面我們獲得了幾個信息:
我們對我們已有的設備反復試驗,確實了只有Adreno的設備(小米3,HTC M8,華為P7等)會在特定條件下出現這種奇奇怪怪的隨機Crash。而其他設備例如小米Pad(Tegra),三星S3(Mali)等都不會出現這種問題。這個問題確實頭疼,在網上搜索了很久也沒找到有用的信息。直到在某次小米3上再次測試的時候,發現了log裡面還有一條必然出現的信息:
E/MemoryHeapBase(18703): error creating ashmem region: Too many open files
這個信息間接的指出了問題,也給了我們一些提示:似乎打開了過多的文件。於是靠著這個靈光,我們嘗試著在程序中輸出所有已打開的文件:
SHOW FILE HANDLES:
0 (socket:[285038]): read-write
1 (/dev/null): read-write
2 (/dev/null): read-write
3 (/dev/log/main): cloexec write-only
4 (/dev/log/radio): cloexec write-only
5 (/dev/log/events): cloexec write-only
6 (/dev/log/system): cloexec write-only
7 (/sys/kernel/debug/tracing/trace_marker): write-only
8 (/dev/__properties__):
9 (/dev/binder): cloexec read-write
10 (/dev/log/main): cloexec write-only
11 (/dev/log/radio): cloexec write-only
12 (/dev/log/events): cloexec write-only
13 (/dev/log/system): cloexec write-only
14 (/system/framework/framework-res.apk):
15 (/system/framework/core-libart.jar):
16 (pipe:[282578]): nonblock
17 (/dev/alarm):
18 (/dev/cpuctl/tasks): cloexec write-only
19 (/dev/cpuctl/bg_non_interactive/tasks): cloexec write-only
20 (socket:[282569]): read-write
21 (pipe:[282570]):
22 (pipe:[282570]): write-only
23 (pipe:[282578]): nonblock write-only
24 (anon_inode:[eventpoll]): read-write
25 (/data/app/---app_name---/base.apk):
26 (/data/data/---app_name---/databases/bugly_db): cloexec read-write
27 (socket:[285047]): read-write
28 (anon_inode:mali-8938): cloexec
29 (socket:[282605]): nonblock read-write
30 (socket:[283605]): nonblock read-write
31 (/dev/null): read-write
32 (/dev/ump): read-write
33 (socket:[285045]): nonblock read-write
34 (/dev/null): read-write
35 (/dev/mali): read-write
36 (anon_inode:mali-8938): cloexec
37 (anon_inode:mali-8938): cloexec
38 (/data/app/---app_name---/base.apk):
39 (anon_inode:mali-8938): cloexec
40 (anon_inode:mali-8938): cloexec
41 (/dev/null): read-write
42 (/dev/null): read-write
43 (/data/app/---app_name---/base.apk):
44 (/dev/null): read-write
45 (anon_inode:mali-8938): cloexec
46 (/data/data/---app_name---/files/DefaultFont.ttf):
47 (/data/app/---app_name---/base.apk):
48 (anon_inode:sync_fence):
49 (/dev/null): read-write
50 (socket:[285060]): cloexec read-write
52 (anon_inode:mali-8938): cloexec
53 (anon_inode:mali-8938): cloexec
54 (/dev/null): read-write
55 (anon_inode:sync_fence):
56 (pipe:[284134]): write-only
58 (anon_inode:sync_fence):
62 (anon_inode:sync_fence):
63 (anon_inode:sync_fence):
通過不停測試程序,發現已打開的文件數量一直有增無減,而當這些被打開的文件數量接近1024的時候,上面的eglSwapBuffers必然出錯。於是乎我們得出一個中間結論:
這從字面上看著似乎有些扯淡,因為這兩者總感覺沒啥聯系。這個問題只會出現在Adreno的GPU上面,於是我們猜想:
這樣看起來似乎就比較有道理了。雖然sawp buffer本身是不會Crash的,他並沒有raise任何signal,只是簡單的返回了一個錯誤的結果,但這會導致上層邏輯出現異常。這些異常在不同的設備上表現不一樣:
於是這就有了各種奇奇怪怪的Crash。
通過對代碼的排查,我們發現在使用SoundPool處理音效的時候,確實存在FD洩露的情況:
1 private SoundPool m_soundPool;
2 public int loadSound(String path) {
3 int soundID = m_soundPool.load(getAssets().openFd(path), 0);
4 return soundID;
5 }
6 public unloadSound(int soundID) {
7 m_soundPool.unload(soundID);
8 }
雖然我們在不需要這些音效的時候,對其進行了卸載處理,但不知道是SoundPool類自身的缺陷,還是我們的使用不當,在實際測試中我們發現unload過後,在load中通過openFd打開的FD並沒有被釋放掉。強制調用System.gc()在一些設備(例如小米3)上可以釋放掉這部分FD,但是另一些設備(例如HTC M8)即使強制gc這無法卸載掉它們,於是便出現了FD洩露的情況。
最終我們自行對這些FD進行管理,並且在unload的時候手動調用這些FD的close方法:
1 private SoundPool m_soundPool;
2 private HashMap<Integer, AssetFileDescriptor> m_soundFdMap
3 public int loadSound(String path) {
4 AssetFileDescriptor fd = getAssets().openFd(path);
5 int soundID = m_soundPool.load(fd, 0);
6 m_soundFdMap.put(soundID, fd);
7 return soundID;
8 }
9 public unloadSound(int soundID) {
10 m_soundPool.unload(soundID);
11 m_soundFdMap.get(soundID).close();
12 }
這之後FD再無洩露的情況發生,之前的各種設備上面的各種奇奇怪怪的Crash都被處理好了。
這個問題粗略說起來就是:因為播放了太多的音效,導致Adreno底層渲染失敗,以至於上層邏輯各種失措,產生了很多奇奇怪怪的Crash。准確的解釋應該是:程序中的FD洩露如同內存洩露一樣是同樣需要得到關注的問題,FD的耗盡如同內存的耗盡一樣會導致程序的各種異常情況發生,但是前者不如後者那麼知名也不如後者容易被察覺。
轉自:http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=28
Android自定義控件2--優酷菜單界面初始化,android2--本文開始將逐步去實現下面優酷菜單的效果: 本文地址:http://www.cnblogs.com/
自定義類似於listView中Item背景,listviewitem方法一、 drawable/listitem_bk.xml Xml代碼
使用新版Android Studio檢測內存洩露和性能 內存洩露,是Android開發者最頭疼的事。可能一處小小的內存洩露,都可能是毀於千裡之堤的蟻穴。 怎麼才能檢測內
【React Native開發】React Native控件之ToolbarAndroid工具欄控件講解以及使用(15) (一)前言 今天我們一起來看一下工具欄控件T