6

猜猜看,另一个 Android-Bitmap-OOM 问题!

背景

在对我们的应用程序进行压力测试时,我们注意到,在持续、大量使用(类似猴子跑步者)之后,可以最大限度地利用应用程序的进程内存分配,OutOfMemory并在随后的堆栈跟踪中记录异常。The app downloads images (around 3 at a time) when a page under a ViewPageris selected. 当应用程序的长度和呼吸被锻炼时,可以有 280+ 图像可供下载。该应用程序使用Square 的 Picasso 进行图像下载抽象。值得注意的是,在我们的应用程序代码中,我们没有直接操作位图……我们相信非常有才华的 Square Inc. 员工比我们做得更好。

这是一张图片

下图显示了dalvikvm-heap日志消息下记录的堆分配随时间的变化。红点表示用户将一组新文章带入应用程序,以增加未完成的工作量并给应用程序带来压力……

DALVIKVM 堆分配 http://snag.gy/FgsiN.jpg 图 1: Nexus One 堆分配;OOM 发生在 80MB 以上

调查至今

针对 Nexus S、Nexus 4、Wildfire、HTC Incredible 和无数其他测试设备,轶事测试表明内存管理足以让 DVM GC“跟上”应用程序完成的繁重工作。然而,在 Galaxy S II、III、IV 和 HTC One 等高端设备上,OOM 很普遍。事实上,如果有足够的工作要做,我想我们所有的设备最终都会出现故障。

问题

屏幕密度(我们请求的图像大小基于 ImageView 的大小)、进程内存分配和给定大小的图像数量之间显然存在关系,这将导致应用程序超出其堆限制。我即将着手量化这种关系,但希望 SO 社区将目光投向这个问题,并且 (a) 同意或不同意这种关系值得建立,并且 (b) 提供说明如何最好地制定这种关系的文献。

重要的是要注意,如果我们破坏图像质量,我们的 OOM 都会消失,但是 UX 会更差,这就是为什么我们希望最有效地使用可用堆进行切块。


旁注:这是负责将这些图像加载到已布局的视图中的代码部分;

picassoInstance.load(entry.getKey())
               .resize(imageView.getMeasuredWidth(), 
                       imageView.getMeasuredHeight())
               .centerCrop()
               .into(imageView);

上面提到的“图像质量的冲刺”只是将imageView.getMeasured...4 除以一个数字。

4

2 回答 2

2

首先你需要管理内存分配,这是android中的一个大问题,因为位图占用大量内存,因为可以通过以下方式减少内存分配

  1. 将所有尺寸巨大的图像放入 assets 文件夹,而不是将它们放入可绘制的文件夹中。因为可绘制资源需要内存来缓存它们。如果从资产文件夹加载图像将不会缓存。并且会占用更少的内存。

    1. 研究用于高效内存管理的 Lrucache。
    2. 将资源以微小的格式进行检查TinyPNG
    3. 如果您的图像分辨率太大,请尝试将 SVG 文件用于图像并加载 SVG 文件而不是图像。检查此SVG FOR ANDROID

最后我的英语不是很好希望它可以帮助你。

于 2014-04-03T07:03:28.350 回答
0

这篇文章有点旧,但我最近也遇到了这个问题。也许这会帮助别人。这个庞大线程的一般概述/对我有什么帮助。

-确保您使用的是毕加索的单例实例

- 使用适合()

-对于大图像或许多图像或在 FragmentPager/StatePager 中使用时,您可能应该使用 skipmemorycache() 和/或 largeHeap 声明

阅读主题以获得更多提示。在发布此问题时,没有人在 picassos github 上发布此问题。

https://github.com/square/picasso/issues/305

于 2014-08-14T17:42:39.257 回答