强制纵向模式 OOM 位图调整大小
每当我在 onCreate 中强制使用纵向模式时,
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
都会收到错误
纵向模式与图像规模上的 OOM VM 预算有什么关系?
private void scaleFrom(BmpWrap image, Bitmap bmp)
{
if (image.bmp != null && image.bmp != bmp) {
image.bmp.recycle();
}
if (mDisplayScale > 0.99999 && mDisplayScale < 1.00001) {
image.bmp = bmp;
return;
}
int dstWidth = (int)(bmp.getWidth() * mDisplayScale);
int dstHeight = (int)(bmp.getHeight() * mDisplayScale);
image.bmp = Bitmap.createScaledBitmap(bmp, dstWidth, dstHeight, true);
}
private void resizeBitmaps()
{
scaleFrom(mBackground, mBackgroundOrig);
for (int i = 0; i < mBOrig.length; i++) {
scaleFrom(mB[i], mBOrig[i]);
}
for (int i = 0; i < mBlind.length; i++) {
scaleFrom(mBlind[i], mBlindOrig[i]);
}
for (int i = 0; i < mFrozen.length; i++) {
scaleFrom(mFrozen[i], mFrozenOrig[i]);
}
for (int i = 0; i < mTargeted.length; i++) {
scaleFrom(mTargeted[i], mTargetedOrig[i]);
}
scaleFrom(mBlink, mBlinkOrig);
scaleFrom(mWon, mWonOrig);
scaleFrom(mLost, mLostOrig);
mImagesReady = true;
}
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:498)
at android.graphics.Bitmap.createBitmap(Bitmap.java:465)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:370)
at com.company.app.View$hread.scaleFrom(View.java:313)
at com.company.app.View$hread.resizeBitmaps(View.java:337)
at com.company.app.View$hread.setSurfaceSize(View.java:480)
at com.company.app.View.surfaceChanged(View.java:905)
at android.view.SurfaceView.updateWindow(SurfaceView.java:538)
at android.view.SurfaceView.dispatchDraw(SurfaceView.java:339)
at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.View.draw(View.java:6745)
at android.widget.FrameLayout.draw(FrameLayout.java:352)
at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.View.draw(View.java:6745)
at android.widget.FrameLayout.draw(FrameLayout.java:352)
at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1891)
at android.view.ViewRoot.draw(ViewRoot.java:1416)
at android.view.ViewRoot.performTraversals(ViewRoot.java:1172)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1736)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:4701)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
Whenever I force portrait mode in onCreate
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
I get an error
What does Portrait mode have to do with OOM VM budget on image scale?
private void scaleFrom(BmpWrap image, Bitmap bmp)
{
if (image.bmp != null && image.bmp != bmp) {
image.bmp.recycle();
}
if (mDisplayScale > 0.99999 && mDisplayScale < 1.00001) {
image.bmp = bmp;
return;
}
int dstWidth = (int)(bmp.getWidth() * mDisplayScale);
int dstHeight = (int)(bmp.getHeight() * mDisplayScale);
image.bmp = Bitmap.createScaledBitmap(bmp, dstWidth, dstHeight, true);
}
private void resizeBitmaps()
{
scaleFrom(mBackground, mBackgroundOrig);
for (int i = 0; i < mBOrig.length; i++) {
scaleFrom(mB[i], mBOrig[i]);
}
for (int i = 0; i < mBlind.length; i++) {
scaleFrom(mBlind[i], mBlindOrig[i]);
}
for (int i = 0; i < mFrozen.length; i++) {
scaleFrom(mFrozen[i], mFrozenOrig[i]);
}
for (int i = 0; i < mTargeted.length; i++) {
scaleFrom(mTargeted[i], mTargetedOrig[i]);
}
scaleFrom(mBlink, mBlinkOrig);
scaleFrom(mWon, mWonOrig);
scaleFrom(mLost, mLostOrig);
mImagesReady = true;
}
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:498)
at android.graphics.Bitmap.createBitmap(Bitmap.java:465)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:370)
at com.company.app.View$hread.scaleFrom(View.java:313)
at com.company.app.View$hread.resizeBitmaps(View.java:337)
at com.company.app.View$hread.setSurfaceSize(View.java:480)
at com.company.app.View.surfaceChanged(View.java:905)
at android.view.SurfaceView.updateWindow(SurfaceView.java:538)
at android.view.SurfaceView.dispatchDraw(SurfaceView.java:339)
at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.View.draw(View.java:6745)
at android.widget.FrameLayout.draw(FrameLayout.java:352)
at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.View.draw(View.java:6745)
at android.widget.FrameLayout.draw(FrameLayout.java:352)
at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1891)
at android.view.ViewRoot.draw(ViewRoot.java:1416)
at android.view.ViewRoot.performTraversals(ViewRoot.java:1172)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1736)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:4701)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
每当您更改方向时,除了静态属性外,应用程序都会完全重新加载。 (阅读此处:http://developer.android.com/reference/android/app /Activity.html)
这意味着您分配的所有位图(如果它们不是静态的)都将被重新加载。
由于一个应用程序允许的内存为 16 MB(我听说在某些设备上为 24 MB),并且该位图作为原始位图存储在内存中(读取未压缩),这会导致内存使用量激增,从而导致
OOM事实上,用于位图的内存是在堆内存之外分配的,但被视为堆内存的一部分,因此即使使用 ddms 或 MAT,您也无法实际跟踪该问题。
请务必在 onDestroy 方法中回收所有位图,以便可以对它们进行垃圾收集。
最终让我摆脱这个困境的一件事是这三行代码(hack):
不过请注意,它会影响性能(大约 500 到 750 毫秒),因此它不适合关注 FPS 的游戏,但适合它的应用程序是完全合理的。
将它们放在 createScaledBitmap 调用的最开始处。
它对我有用
编辑:
根据您对相关位图所做的操作,您可以要求 android 以向下采样的方式打开它,从而占用更少的内存。我在处理这个问题的时候写了这个函数。它尝试打开尽可能大的位图:
Whenever you do an orientation change, the app is reloaded entirely except for static properties. (read here : http://developer.android.com/reference/android/app/Activity.html)
This means that all the bitmap you allocated if they were not static will be reloaded.
Since the memory allowed for one app is 16 MB(24 on some devices i hear) and that bitmap are stored in memory as raw bitmap(read not compressed) this create a spike in the memory usage that can lead to OOM
Add to that the fact that the memory used for bitmaps are allocated outside of your heap memory but counted as if part of it so that you can't actually trace that problem even using ddms or MAT.
Be sure to recycle all your bitmaps in your onDestroy method so that they can be garbage collected.
The one thing that finally got me out of this one are these three lines of code(hack) :
Beware though, it impacts performance(about 500 to 750 ms) so it is not suitable for a game with FPS concern but for an app it is perfectly reasonable.
Put them at the very beginning of your createScaledBitmap call.
It worked for me
Edit :
Depending on what you are doing with the bitmap in question you can ask android to open it downsampled, taking less memory. I wrote this function while dealing with this problem. It tries to open the bitmap as big as possible :
OOM 异常是因为您通过在方向更改时重新创建位图来耗尽本机堆。请参阅我的帖子 BitmapFactory OOM 让我发疯 了解背景信息。
解决这个问题的一种方法是(正如 Yahel 所说)在 onDestroy 中回收位图。虽然位图数据在Native堆中,但我们发现下面形式的代码(在onDestroy中)对于取回堆更有效。
The OOM exception is because you are running out of Native heap by recreating bitmaps on the orientation change. See my post at BitmapFactory OOM driving me nuts for background.
One way around this is to (as Yahel says) recycle your bitmaps in onDestroy. Although the bitmap data are in the Native heap, and we found that the code of the form below (in onDestroy) is more effective in getting the heap back.