I'm trying to write a small widget to display images from the SDCARD, with a pan/zoom functionality. After realizing most of the images will not fit into memory as fully sampled bitmaps, I'm trying something a bit more complex - I will have a down-sampled bitmap of the entire image for fast panning and zooming, and a hi-res cropped portion of the image of just what's visible on the viewport that will be calculated in the background and drawn over the low-res when it's done (separate thread).
我正在尝试编写一个小小部件来显示来自SDCARD的图像,具有平移/缩放功能。在意识到大部分图像不能作为完全采样的位图进入存储器之后,我正在尝试更复杂的东西 - 我将对整个图像进行下采样位图以进行快速平移和缩放,并进行高分辨率裁剪视口中可见的部分图像将在背景中显示,并在完成后绘制在低分辨率上(单独的线程)。
After allot of searching I finally found the great-and-holly BitmapRegionDecoder that can load a part of the image for me, without memory exceptions in the process.
在分配完搜索之后,我终于找到了可以为我加载图像的一部分的伟大和冬青的BitmapRegionDecoder,在此过程中没有内存异常。
WOO-HOO, right?
WOO-HOO,对吗?
Only... While switching between many images - i found that the BitmapRegionDecoder doesn't really free the memory it's using after a call to recycle() ... the heap just grows and grows until I get the ever frustrating out-of-memory...
只有...在许多图像之间切换时 - 我发现BitmapRegionDecoder并没有真正释放它在调用recycle()之后使用的内存......堆只是增长并且增长直到我得到令人沮丧的外面 - 记忆...
Here's a little loop that demonstrates the problem:
这是一个演示问题的小循环:
new AsyncTask<String, Integer, Void>() {
BitmapRegionDecoder decoder;
@Override
protected Void doInBackground(String... params) {
for (int i=0; i<30;i++){
try {
// get a decoder instance
decoder = BitmapRegionDecoder.newInstance(params[0], false);
// (I'm not even doing anything with it!)
// recycle, null-it, g-collect it, just die already:
decoder.recycle();
decoder=null;
System.gc();
} catch (IOException e) {
e.printStackTrace();
return null;
}
//print the memory usage after each step:
onProgressUpdate(i);
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//just print the heap sizes
Double allocated = Double.valueOf(Debug.getNativeHeapAllocatedSize())/Double.valueOf((1048576));
Double available = Double.valueOf(Debug.getNativeHeapSize())/1048576.0;
Double free = Double.valueOf(Debug.getNativeHeapFreeSize())/1048576.0;
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setMinimumFractionDigits(2);
Log.d("MEM", Integer.toString(values[0]) + " - alloc " + df.format(allocated) + "MB of " + df.format(available) + "MB (" + df.format(free) + "MB free)");
}
}.execute(SOME_LARGE_IMAGE_PATH);
SOME_LARGE_IMAGE_PATH is a 3000x3000 PNG-file (Not so far from the images captured by the camera).
SOME_LARGE_IMAGE_PATH是一个3000x3000的PNG文件(距离相机拍摄的图像不远)。
Ran on an emulator with API-10.
使用API-10在模拟器上运行。
Here is the LogCat, filtered for just MEM TAG:
这是LogCat,仅针对MEM TAG进行过滤:
0 - alloc 11.44MB of 18.95MB (0.09MB free)
1 - alloc 18.40MB of 25.98MB (0.10MB free)
2 - alloc 25.38MB of 32.96MB (0.10MB free)
3 - alloc 32.36MB of 39.94MB (0.10MB free)
4 - alloc 39.35MB of 46.92MB (0.10MB free)
5 - alloc 46.33MB of 53.90MB (0.10MB free)
6 - alloc 53.31MB of 60.88MB (0.10MB free)
7 - alloc 60.30MB of 67.87MB (0.10MB free)
8 - alloc 67.28MB of 74.85MB (0.09MB free)
9 - alloc 74.26MB of 81.83MB (0.09MB free)
10 - alloc 81.24MB of 88.81MB (0.09MB free)
11 - alloc 88.23MB of 95.79MB (0.09MB free)
12 - alloc 95.21MB of 102.78MB (0.09MB free)
13 - alloc 102.19MB of 109.76MB (0.09MB free)
14 - alloc 109.17MB of 116.74MB (0.09MB free)
15 - alloc 116.16MB of 123.72MB (0.09MB free)
16 - alloc 123.14MB of 130.70MB (0.09MB free)
17 - alloc 130.12MB of 137.69MB (0.09MB free)
18 - alloc 137.11MB of 144.67MB (0.09MB free)
19 - alloc 144.09MB of 151.65MB (0.09MB free)
20 - alloc 151.07MB of 158.63MB (0.09MB free)
21 - alloc 158.05MB of 165.61MB (0.10MB free)
22 - alloc 165.04MB of 172.61MB (0.09MB free)
23 - alloc 172.02MB of 179.59MB (0.09MB free)
24 - alloc 179.00MB of 186.57MB (0.09MB free)
25 - alloc 185.45MB of 193.55MB (0.16MB free)
26 - alloc 192.44MB of 200.07MB (0.16MB free)
and then it crashed....
然后它崩溃了....
and the full LogCat:
和完整的LogCat:
0 - alloc 11.44MB of 18.95MB (0.09MB free)
GC_EXPLICIT freed 37K, 51% free 2644K/5379K, external 2043K/2137K, paused 47ms
1 - alloc 18.40MB of 25.98MB (0.10MB free)
GC_EXPLICIT freed 41K, 51% free 2637K/5379K, external 2043K/2137K, paused 55ms
2 - alloc 25.38MB of 32.96MB (0.10MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 46ms
3 - alloc 32.36MB of 39.94MB (0.10MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 54ms
4 - alloc 39.35MB of 46.92MB (0.10MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 48ms
5 - alloc 46.33MB of 53.90MB (0.10MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 59ms
6 - alloc 53.31MB of 60.88MB (0.10MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 47ms
7 - alloc 60.30MB of 67.87MB (0.10MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 54ms
8 - alloc 67.28MB of 74.85MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 66ms
9 - alloc 74.26MB of 81.83MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 91ms
10 - alloc 81.24MB of 88.81MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 75ms
11 - alloc 88.23MB of 95.79MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 56ms
12 - alloc 95.21MB of 102.78MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 46ms
13 - alloc 102.19MB of 109.76MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 53ms
14 - alloc 109.17MB of 116.74MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 57ms
15 - alloc 116.16MB of 123.72MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 61ms
16 - alloc 123.14MB of 130.70MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 47ms
17 - alloc 130.12MB of 137.69MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 56ms
18 - alloc 137.11MB of 144.67MB (0.09MB free)
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 56ms
19 - alloc 144.09MB of 151.65MB (0.09MB free)
Process com.android.settings (pid 166) has died.
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 58ms
20 - alloc 151.07MB of 158.63MB (0.09MB free)
Process com.android.deskclock (pid 262) has died.
Process com.android.music (pid 204) has died.
Process com.yakstudio.moody (pid 287) has died.
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 52ms
21 - alloc 158.05MB of 165.61MB (0.10MB free)
Process com.android.email (pid 275) has died.
Process android.process.media (pid 231) has died.
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 55ms
22 - alloc 165.04MB of 172.61MB (0.09MB free)
Process com.android.defcontainer (pid 427) has died.
Process com.svox.pico (pid 440) has died.
Process com.android.quicksearchbox (pid 218) has died.
Low Memory: No more background processes.
purging 38K from font cache [5 entries]
GC_EXPLICIT freed 125K, 51% free 2771K/5639K, external 2168K/2674K, paused 107ms
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 46ms
23 - alloc 172.02MB of 179.59MB (0.09MB free)
Process com.android.launcher (pid 150) has died.
Low Memory: No more background processes.
WIN DEATH: Window{40735be0 com.android.launcher/com.android.launcher2.Launcher paused=false}
purging 6K from font cache [1 entries]
GC_EXPLICIT freed 183K, 50% free 2925K/5767K, external 1625K/2137K, paused 113ms
GC_EXPLICIT freed 33K, 51% free 2637K/5379K, external 2043K/2137K, paused 60ms
24 - alloc 179.00MB of 186.57MB (0.09MB free)
purging 67K from font cache [6 entries]
GC_EXPLICIT freed 1K, 51% free 2669K/5379K, external 2043K/2137K, paused 83ms
purging 141K from font cache [14 entries]
GC_EXPLICIT freed 230K, 49% free 4217K/8263K, external 3125K/3903K, paused 190ms
GC_EXPLICIT freed 69K, 52% free 2600K/5379K, external 1645K/2137K, paused 67ms
25 - alloc 185.45MB of 193.55MB (0.16MB free)
Process jp.co.omronsoft.openwnn (pid 124) has died.
Scheduling restart of crashed service jp.co.omronsoft.openwnn/.OpenWnnJAJP in 5000ms
Low Memory: No more background processes.
Session failed to close due to remote exception
android.os.DeadObjectException
at android.os.BinderProxy.transact(Native Method)
at com.android.internal.view.IInputMethodSession$Stub$Proxy.finishSession(IInputMethodSession.java:346)
at com.android.server.InputMethodManagerService.finishSession(InputMethodManagerService.java:896)
at com.android.server.InputMethodManagerService.clearCurMethodLocked(InputMethodManagerService.java:907)
at com.android.server.InputMethodManagerService.onServiceDisconnected(InputMethodManagerService.java:924)
at android.app.LoadedApk$ServiceDispatcher.doDeath(LoadedApk.java:1069)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1083)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at com.android.server.ServerThread.run(SystemServer.java:540)
Session failed to close due to remote exception
android.os.DeadObjectException
at android.os.BinderProxy.transact(Native Method)
at com.android.internal.view.IInputMethodSession$Stub$Proxy.finishSession(IInputMethodSession.java:346)
at com.android.server.InputMethodManagerService.finishSession(InputMethodManagerService.java:896)
at com.android.server.InputMethodManagerService.clearCurMethodLocked(InputMethodManagerService.java:911)
at com.android.server.InputMethodManagerService.onServiceDisconnected(InputMethodManagerService.java:924)
at android.app.LoadedApk$ServiceDispatcher.doDeath(LoadedApk.java:1069)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1083)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at com.android.server.ServerThread.run(SystemServer.java:540)
Start proc jp.co.omronsoft.openwnn for service jp.co.omronsoft.openwnn/.OpenWnnJAJP: pid=723 uid=10004 gids={}
GC_EXPLICIT freed 10K, 53% free 2538K/5379K, external 1625K/2137K, paused 201ms
GC_EXPLICIT freed <1K, 53% free 2538K/5379K, external 1625K/2137K, paused 228ms
GC_EXPLICIT freed <1K, 53% free 2538K/5379K, external 1625K/2137K, paused 158ms
No JNI_OnLoad found in /system/lib/libwnndict.so 0x40515658, skipping init
GC_CONCURRENT freed 1052K, 55% free 3079K/6727K, external 1625K/2137K, paused 9ms+8ms
Ignoring onBind: cur seq=12, given seq=15
GC_EXPLICIT freed 34K, 52% free 2600K/5379K, external 1645K/2137K, paused 92ms
26 - alloc 192.44MB of 200.07MB (0.16MB free)
Process jp.co.omronsoft.openwnn (pid 723) has died.
Scheduling restart of crashed service jp.co.omronsoft.openwnn/.OpenWnnJAJP in 20000ms
Low Memory: No more background processes.
Session failed to close due to remote exception
android.os.DeadObjectException
at android.os.BinderProxy.transact(Native Method)
at com.android.internal.view.IInputMethodSession$Stub$Proxy.finishSession(IInputMethodSession.java:346)
at com.android.server.InputMethodManagerService.finishSession(InputMethodManagerService.java:896)
at com.android.server.InputMethodManagerService.clearCurMethodLocked(InputMethodManagerService.java:907)
at com.android.server.InputMethodManagerService.onServiceDisconnected(InputMethodManagerService.java:924)
at android.app.LoadedApk$ServiceDispatcher.doDeath(LoadedApk.java:1069)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1083)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at com.android.server.ServerThread.run(SystemServer.java:540)
Session failed to close due to remote exception
android.os.DeadObjectException
at android.os.BinderProxy.transact(Native Method)
at com.android.internal.view.IInputMethodSession$Stub$Proxy.finishSession(IInputMethodSession.java:346)
at com.android.server.InputMethodManagerService.finishSession(InputMethodManagerService.java:896)
at com.android.server.InputMethodManagerService.clearCurMethodLocked(InputMethodManagerService.java:911)
at com.android.server.InputMethodManagerService.onServiceDisconnected(InputMethodManagerService.java:924)
at android.app.LoadedApk$ServiceDispatcher.doDeath(LoadedApk.java:1069)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1083)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at com.android.server.ServerThread.run(SystemServer.java:540)
Process com.ykstudio.ykLibDemo (pid 626) has died.
WIN DEATH: Window{4069b908 com.ykstudio.ykLibDemo/com.ykstudio.ykLibDemo.MainActivity paused=false}
channel '406fd480 com.ykstudio.ykLibDemo/com.ykstudio.ykLibDemo.SuperImageViewActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x8
channel '406fd480 com.ykstudio.ykLibDemo/com.ykstudio.ykLibDemo.SuperImageViewActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
WIN DEATH: Window{406fd480 com.ykstudio.ykLibDemo/com.ykstudio.ykLibDemo.SuperImageViewActivity paused=false}
Start proc com.ykstudio.ykLibDemo for activity com.ykstudio.ykLibDemo/.MainActivity: pid=734 uid=10035 gids={}
Low Memory: No more background processes.
Got RemoteException sending setActive(false) notification to pid 626 uid 10035
Displayed com.ykstudio.ykLibDemo/.MainActivity: +1s306ms
Help! Any thoughts?...
帮帮我!有什么想法吗?...
1 个解决方案
#1
0
If I understand the documentation correctly, you can reuse the BitmapRegionDecoder without the need to reinstantiate it every time you will use it. Did you try to just reuse it?
如果我正确理解文档,您可以重复使用BitmapRegionDecoder,而无需在每次使用它时重新实例化它。你试过重用它吗?
And I must agree: everybody writes that the BitmapRegionDecoder should be used for this scenario (display large bitmaps without running into OOM), but nobody knows exactly how to use it the right way :(
我必须同意:每个人都写道BitmapRegionDecoder应该用于这种情况(显示大型位图而不会运行到OOM中),但没有人确切知道如何以正确的方式使用它:(
#1
0
If I understand the documentation correctly, you can reuse the BitmapRegionDecoder without the need to reinstantiate it every time you will use it. Did you try to just reuse it?
如果我正确理解文档,您可以重复使用BitmapRegionDecoder,而无需在每次使用它时重新实例化它。你试过重用它吗?
And I must agree: everybody writes that the BitmapRegionDecoder should be used for this scenario (display large bitmaps without running into OOM), but nobody knows exactly how to use it the right way :(
我必须同意:每个人都写道BitmapRegionDecoder应该用于这种情况(显示大型位图而不会运行到OOM中),但没有人确切知道如何以正确的方式使用它:(