有没有一种方法在安卓系统中压缩内存以降低高水位线?

9
请注意,我并没有内存泄漏。我的问题与更微妙的问题有关。
最近我编写了一个Android应用程序,用于图像处理。图像作为位图加载,然后以像素形式复制出来,在使用大量内存的方式下进行处理(例如浮点表示中的傅里叶变换等),然后转换回位图并保存。
问题是,至少在Android OS 2.3及以下版本中,总内存限制(通常为16MB)是Java和(外部存储的)位图的组合,而当内存被释放(成功GC'd)时,Java高水位线不会下降(据我所知),这意味着当我要分配最终的位图时,即使在那时我已经释放了(并GC'd了)大部分空间,我经常会“内存不足”。也就是说,我从来不需要一次性使用全部16MB,但是留给位图的空间似乎是16MB减去MAX历史Java堆使用情况(而不是当前使用情况)。
我看了一个由Android开发人员之一提供的技术讲座,讲述了内存问题,他暗示这个问题已经在操作系统的后续版本中得到解决(他们将位图内存移入Java堆空间),但同时大多数想使用我的应用程序的人正在运行2.2或2.3。
长话短说,我想知道Java堆是否会被压缩(在实际上被碎片化的情况下),以便高水位线收缩(如果有的话,如何使其发生)?
如果不是这样,那么有没有其他建议来解决这个问题?

是的,这是一个麻烦的问题。在Acer Liquid上尤其严重。 - Dmitry Ryadnenko
我猜SQLite本地代码也存在类似的问题。游标本地初始化方法经常会出现类似的症状。 - Dmitry Ryadnenko
3个回答

1
长话短说,我想知道Java堆是否会被压缩(即碎片整理),以便高水位线缩小(如果是这样的话,如何实现)?
无论其行为如何,它肯定不在您的控制之下。
如果不行,那么有没有其他建议来解决这个问题?
理想情况下,重复使用自己的位图。您没有说明“以使用大量内存的方式处理”到底是什么。但是,如果它不改变图像的尺寸或位深度,则将数据复制回原始位图而不是分配新的位图,如果可以的话。
Android 2.x上的图像处理是我可以看到正当使用多个进程的少数几个地方之一。您将增加在进程之间传输图像数据的开销,但是另一个进程具有自己的堆(Java和本机),因此这可能会给您更多的“活动空间”。

我最初想要重用原始位图,因为输出实际上是相同的,但问题在于当你从文件解码位图时,返回的位图是不可变的。(有一个标志可以“请求”它是可变的,但在2.3中没有。)在我的情况下,单独的进程帮助不大,因为几乎所有的内存都被位图加载->处理->位图保存的链使用。(我想出了一个效果不佳但可行的解决方案,我会将其发布为答案。)我将更新我的描述以澄清“以某种方式处理...”。 - Brandyn

1

到目前为止,没有迹象表明有任何方法可以压缩内存。

这是我的解决方法,虽然不太理想,但比以前的行为要好得多:

我现在故意保留原始位图,同时进行处理,然后回收(recycle())并将其设置为空(null),并进行垃圾回收(GC()),但要在分配输出位图之前才这样做。

这样做会保留外部(位图)空间,并导致我的应用程序在处理期间耗尽Java堆(在调用recycle()之前),我至少可以通过重试较小的图像来捕获和处理它(在此之前,一切似乎都很好,直到我尝试保存,但那时已经太晚了,也没有办法恢复。)

从技术上讲,这限制了我的最大图像大小,小于我应该能够使用分配的内存(因为我需要同时在堆和外部中保留空间,而实际上我永远不需要两者同时存在),但至少我仍然可以处理合理的图像大小。

以前发生的情况是我会早期释放和回收位图,这使得Java堆上的高水位线基本上使用了我所有的内存分配,这意味着从那时起我无法打开或创建任何更多的位图(除了有时是微小的缩略图大小)。

在我看来,这是 Android 处理 Bitmap 内存的一个重大 bug,但我相信它已经在较新版本的操作系统中得到了修复,因此希望我可以根据操作系统版本条件地禁用此解决方法。

只是一点提醒:你可能已经意识到了,但是调用System.gc()并不会立即触发垃圾回收。它只是向系统发出请求,系统会在适当的时机进行回收... - Pedro Loureiro
我认为这个问题值得在官方的 Android 邮件列表中讨论。幸运的是,有谷歌的人会来帮你解决。 - Pedro Loureiro

0

我假设你已经调用了Bitmap.recycle(),但这是我唯一记得的事情,你没有谈论它。


是的,我有一个与此相关的糟糕解决方案 - 请查看我在另一个线程中即将发表的评论。 - Brandyn
1
我刚刚偶然发现了这篇文章。它可能会有用!https://dev59.com/puo6XIcBkEYKwwoYTzNK - Pedro Loureiro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接