【问题标题】:Picasso Library - Out of Memory毕加索图书馆 - 内存不足
【发布时间】:2017-07-08 05:00:55
【问题描述】:

我在我的应用程序中使用 Picasso 库最新版本 2.4.0 来下载和缓存图像。大约有 25-30 张大小为 300KB-400KB 的图像。我认为这绝不是一件大事或沉重的事。

尽管应用程序运行良好,但我的 logcat 中的内存分配已用完。谁能解释为什么会这样?

在 GridView 适配器中加载图像的代码:

Picasso.with(mContext).load(getUrl()).placeholder(R.drawable.placeholder)
            .into(viewholder.image);

这是我的 Logcat 输出:

I/dalvikvm-heap(11142): Grow heap (frag case) to 53.860MB for 2720016-byte allocation
I/dalvikvm-heap(11142): Forcing collection of SoftReferences for 3265936-byte allocation
E/dalvikvm-heap(11142): Out of memory on a 3265936-byte allocation.
I/dalvikvm(11142): "Picasso-/images/posters/34.71.jpg" prio=5 tid=18 RUNNABLE
I/dalvikvm(11142):   | group="main" sCount=0 dsCount=0 obj=0x4283f248 self=0x60a47830
I/dalvikvm(11142):   | sysTid=11196 nice=10 sched=0/0 cgrp=apps/bg_non_interactive I/dalvikvm(11142):   | state=R schedstat=( 2070202497 1858185620 3947 ) utm=172 stm=35 core=3
I/dalvikvm(11142):   at android.graphics.Bitmap.nativeCreate(Native Method)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:726)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:703)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:636)
I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.transformResult(BitmapHunter.I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.hunt(BitmapHunter.java:168)
I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.run(BitmapHunter.java:111)
I/dalvikvm(11142):   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390I/dalvikvm(11142):   at java.util.concurrent.FutureTask.run(FutureTask.java:234)
I/dalvikvm(11142):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.I/dalvikvm(11142):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.I/dalvikvm(11142):   at java.lang.Thread.run(Thread.java:841)
I/dalvikvm(11142):   at com.squareup.picasso.Utils$PicassoThread.run(Utils.java:408)
I/dalvikvm-heap(11142): Forcing collection of SoftReferences for 3265936-byte allocation
E/dalvikvm-heap(11142): Out of memory on a 3265936-byte allocation.
I/dalvikvm(11142): "Picasso-/images/posters/34.71.jpg" prio=5 tid=17 RUNNABLE
I/dalvikvm(11142):   | group="main" sCount=0 dsCount=0 obj=0x42841b88 self=0x5ec91f90
I/dalvikvm(11142):   | sysTid=11183 nice=10 sched=0/0 cgrp=apps/bg_non_interactive I/dalvikvm(11142):   | state=R schedstat=( 2050467088 1713164574 3713 ) utm=172 stm=32 core=3
I/dalvikvm(11142):   at android.graphics.Bitmap.nativeCreate(Native Method)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:726)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:703)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:636)
I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.transformResult(BitmapHunter.I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.hunt(BitmapHunter.java:168)
I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.run(BitmapHunter.java:111)
I/dalvikvm(11142):   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390I/dalvikvm(11142):   at java.util.concurrent.FutureTask.run(FutureTask.java:234)
I/dalvikvm(11142):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.I/dalvikvm(11142):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.I/dalvikvm(11142):   at java.lang.Thread.run(Thread.java:841)
I/dalvikvm(11142):   at com.squareup.picasso.Utils$PicassoThread.run(Utils.java:408)

【问题讨论】:

  • “我认为这不是什么大的或沉重的”——这些图像是巨大的。压缩PNG和JPEG等图像文件;这些图像的堆空间将是几 MB。
  • @CommonsWare 我说考虑到相机图像比那些大 20-30 倍。感谢您为我指明正确的方向。我应该担心还是忽略这个问题,因为应用程序运行良好。
  • “我说过考虑到相机图像比那些大 20-30 倍”——您也不能一次将 25-30 个全分辨率相机图像加载到内存中。 “应用程序运行良好” - 不,您的应用程序正在崩溃,正如您的堆栈跟踪所证明的那样。您需要让 Picasso 将图像下采样到与您的 GridView 相关的大小,例如通过在上面显示的代码中链接对 fit() 的调用。
  • @CommonsWare WowW。只需添加 .fit() 即可解决问题,logcat 中不再出现内存不足。此外,RAM 使用量已从 70MB 变为 40MB。很高兴我问了这个问题。
  • 也许下一个答案可以帮助你stackoverflow.com/questions/24916867/…

标签: android picasso


【解决方案1】:

您的原始代码是下载完整图像,将完整图像加载到内存中,然后让 Android 缩小图像以适应您的 ImageView

在这种情况下,您不需要内存中的完整图像 - 您需要大小接近 ImageView 的大小。

毕加索上的fit() 处理这个问题。它在BitmapFactory.Options 上使用inSampleSize 在图像被加载到内存时对其进行下采样,以得到ImageView 大小的东西,让Android 从那里扩展。这将显着减少每个图像的内存占用,尤其取决于您使用的 ImageView 的大小。

【讨论】:

  • .fit() 并不完美。简单地调用 .fit() 比以前更好,但在快速滚动时仍然会导致内存异常。使用尺寸调用 resize() 完全解决了这个问题。
  • @AdeelAhmad:嗯……出于某种原因,我认为fit() 做了一个resize(),但我可能记错了。很高兴它对你有用!
  • 我刚刚检查了源代码,fit() 确实会调用 resize()——如果目标有大小或目标有大小后立即调用。
  • @CommonsWare,如果fit() 被调用,它会调用。查看函数RequestCreator.into(target, callback)
【解决方案2】:

注意 .fit()!

通过将设备屏幕宽度发送到服务器,并为设备提供正确的图像,最好从服务器提供正确的图像尺寸。这样你就不需要做缩放了。

【讨论】:

  • 我猜服务器应该有一组预先缩放的图像以避免过多的额外计算,但听起来是个好主意。
【解决方案3】:

提到 .fit() 时,其他所有答案听起来都不错。

我认为提及 .fit 的缺点可能会很有趣:

fit() 正在测量目标 ImageView 的尺寸,并在内部使用 resize() 将图像尺寸减小到 ImageView 的尺寸。关于 fit() 有两件事需要了解。首先,调用 fit() 会延迟图像请求,因为 Picasso 需要等到可以测量 ImageView 的大小。其次,您只能将 fit() 与 ImageView 作为目标一起使用(我们稍后会查看其他目标)。

优点是图像的分辨率尽可能低,而不会影响其质量。较低的分辨率意味着要保存在缓存中的数据较少。这可以显着减少图像对应用程序内存占用的影响。总而言之,如果您更喜欢较低的内存影响而不是更快的加载时间,那么 fit() 是一个很好的工具。

TLDR:

  • 只能与 ImageView 目标一起使用
  • 可能会减慢加载速度

来源:https://futurestud.io/tutorials/picasso-image-resizing-scaling-and-fit

【讨论】:

    【解决方案4】:

    应该这样

    Picasso.with(mContext).load(getUrl()).fit().placeholder(R.drawable.placeholder)
            .into(viewholder.image);
    

    【讨论】:

      猜你喜欢
      • 2014-10-29
      • 2014-10-02
      • 1970-01-01
      • 2014-10-10
      • 2016-04-18
      • 1970-01-01
      • 2020-02-22
      • 1970-01-01
      • 2014-08-21
      相关资源
      最近更新 更多