我的 Android 应用程序中遇到了一堆奇怪的(而且很难发现)内存泄漏。我没有任何静态位图(这是所有有关泄漏位图的教程告诉您不要做的事情)。不过,我确实有一个位图存储在我的应用程序类中,我的许多活动正在使用该位图。当最后一个活动退出时,我正在调用 recycle()
,但我想知道将数据存储为 byte[]
并创建是否会更安全在每个使用它的 Activity 中本地生成一个 Bitamp,然后在完成后立即释放它。我很好奇 byte[] 的构造是 VM 比 Bitmap 更容易进行垃圾收集(它似乎完全糟糕)。
非常感谢所有帮助。
I'm experiencing a bunch of wacky (and very hard to find) memory leakage in my Android app. I don't have any static Bitmaps (which is what all the tutorials regarding leaking Bitamps tell you not to do). I do however, have a Bitmap that I'm storing in my Application class which is being used by a bunch of my activities. I AM calling recycle()
on that when the last activity exits, but I'm wondering if it would be safer to just store the data as a byte[]
and create a Bitamp out of it locally in each Activity that uses it, and then release it as soon as it's done. I'm curious of byte[]
is construct that the VM has an easier time garbage collecting than the Bitmap (which it seems to totally suck at).
All help GREATLY appreciated.
发布评论
评论(3)
从
Bitmap
更改为byte[]
并不能解决问题,这是由维护对Bitmap
对象的引用引起的。当最后一个 Activity 退出时,您应该将引用设置为null
,而不是调用recycle()
。这将完成调用recycle()
所做的一切,并允许 GC 获取Bitmap
对象本身。 (GC 在回收时不区分Bitmap
和byte[]
。未引用的对象就是未引用的对象...)唯一需要建议的其他事项(如果
Bitmap
确实是内存泄漏的根源)是使用WeakReference
在您的应用程序类中而不是硬引用。然后每个活动都可以get()
实际的Bitmap
(如果它仍然存在)。那么你不必将其设置为null
;当没有硬引用时,GC 将自动收集位图,留下一个空的弱引用。Changing from a
Bitmap
to abyte[]
isn't going to solve the problem, which is caused by maintaining a reference to theBitmap
object. Instead of callingrecycle()
, you should set the reference tonull
when the last activity exits. That will do everything that callingrecycle()
does plus allows the GC to harvest theBitmap
object itself. (The GC doesn't distinguish betweenBitmap
andbyte[]
when it comes to recycling. An unreferenced object is an unreferenced object...)The only other thing to suggest (if the
Bitmap
really is the source of your memory leak) is to use aWeakReference<Bitmap>
in your application class instead of a hard reference. Then each activity canget()
the actualBitmap
(if it's still there). Then you don't have to set it tonull
; the GC will automatically harvest theBitmap
when there are no hard references, leaving behind an empty weak reference.如果您正在处理从相机拍摄的位图,您需要非常小心图像的大小。
用相机拍摄的照片可能会很大。当您以位图形式打开图像时,您正在将整个数组加载到内存中。考虑一下配备 5MP 摄像头的 Nexus One。用户使用该设备拍摄的照片最大可达 2048x1536。使用 24 位像素深度,我们谈论的是近 9MB。如果考虑到 16/24 MB 堆限制,这将是巨大。
解决方案是使用较小的尺寸,通常您不需要完整尺寸的图像,因为设备的分辨率要低得多,再加上您的
ImageView
(或您用来显示的任何其他表面)的尺寸显示位图)通常不会占据整个屏幕。BitmapFactory.decodeByteArray(...)
(和其他工厂方法)可以采用BitmapFactory.Options
对象,其中您可以通过inSampleSize
。这不会影响原始数据,因此您可以保留全尺寸图像并在内存中获取采样位图。您可以将其结合起来,之前使用inJustDecodeBounds = true
读取图像的大小,然后根据图像的大小和视口的大小计算比例因子,最后获得缩放后的位图。这个问题可能很方便(不是所选的答案,而是其他两个得分较高的答案): 将图像加载到位图对象时出现奇怪的内存不足问题
编辑:哎呀,发布了错误的问题链接
If you are dealing with bitmaps taken from the camera you need to be very careful with the size of the images.
A picture taken with the camera can be pretty big. When you open the image as a bitmap, you are loading the full array into memory. Consider the Nexus One with a 5MP camera. User pictures taken with the device can be as big as 2048x1536. Using 24 bits pixel depth, we are talking about nearly 9MB. This is huge if take into account the 16/24 MB heap limit.
Solution is to work with a smaller size, usually you won't need the full sized image since the device will have a much lower resolution, plus the size of your
ImageView
(or any other surface you use to display the bitmap) won't usually take all the screen.BitmapFactory.decodeByteArray(...)
(and other factory methods) can take aBitmapFactory.Options
object where you can specify a scale factor throughinSampleSize
. This doesn't affect the original data, so you can keep your full size image and get a sampled bitmap in memory. You can combine this by previously usinginJustDecodeBounds = true
to read the size of the image, then calculate the scale factor based on the size of the image and the size of your viewport and finally obtain the scaled bitmap.This question might be handy (not the chosen answer, but the other two with high score): Strange out of memory issue while loading an image to a Bitmap object
Edit: oops, posted wrong link to question
我知道这个问题已经得到解答,但作为旁注:在处理 Bitamp 时,它是 Android 本地处理的事情之一(即通过 C 代码,而不是 Java 代码)。因此,即使您释放对它的所有引用,它仍然会存储在本机端的内存中并计入您的应用程序。
I know this question has already been answered, but just as a side note: When dealing with Bitamps, it's one of those things that Android handles natively (ie through C code, not Java code). So even if you release all references to it, it'll still be stored in memory on the native side and count against your app.