每个图像加载堆都会增长

时间:2015-09-19 11:44:38

标签: java android performance memory garbage-collection

在我的项目中,我有最简单的listview和适配器,使用Picasso加载图像。每个解码图像大约140-150千字节.. 但是在最初的30-60秒内(毕加索记忆LruCache填充)滚动是滞后的。

以下是logcat的一部分:

09-19 14:11:01.435    4676-5700/com.test D/dalvikvm﹕ GC_FOR_ALLOC freed 270K, 11% free 34374K/38228K, paused 60ms, total 61ms
09-19 14:11:01.435    4676-5700/com.test I/dalvikvm-heap﹕ Grow heap (frag case) to 34.487MB for 148408-byte allocation
09-19 14:11:01.505    4676-4676/com.test D/dalvikvm﹕ GC_FOR_ALLOC freed 9K, 11% free 34510K/38376K, paused 66ms, total 66ms
09-19 14:11:06.875    4676-5701/com.test D/dalvikvm﹕ GC_FOR_ALLOC freed 132K, 11% free 34497K/38376K, paused 39ms, total 39ms
09-19 14:11:06.875    4676-5701/com.test I/dalvikvm-heap﹕ Grow heap (frag case) to 34.606MB for 147760-byte allocation
09-19 14:11:06.915    4676-4676/com.test D/dalvikvm﹕ GC_FOR_ALLOC freed <1K, 11% free 34641K/38524K, paused 41ms, total 41ms
09-19 14:11:11.375    4676-5702/com.test D/dalvikvm﹕ GC_FOR_ALLOC freed 110K, 11% free 34650K/38524K, paused 58ms, total 59ms
09-19 14:11:11.385    4676-5702/com.test I/dalvikvm-heap﹕ Grow heap (frag case) to 34.757MB for 149704-byte allocation
09-19 14:11:11.445    4676-4676/com.test D/dalvikvm﹕ GC_FOR_ALLOC freed <1K, 11% free 34796K/38672K, paused 64ms, total 64ms
09-19 14:11:14.615    4676-5699/com.test D/dalvikvm﹕ GC_FOR_ALLOC freed 119K, 11% free 34796K/38672K, paused 53ms, total 53ms
09-19 14:11:14.625    4676-5699/com.test I/dalvikvm-heap﹕ Grow heap (frag case) to 34.900MB for 149704-byte allocation
09-19 14:11:14.655    4676-4676/com.test D/dalvikvm﹕ GC_FOR_ALLOC freed <1K, 10% free 34942K/38820K, paused 37ms, total 37ms

我在这里看到的内容:

堆增长用于非常图像下载和解码。

在堆增长之前,Dalvik尝试GC一些内存。

根据每个GL_FOR_ALLOC,大约有3 MB没有当前的实时堆大小。

对于listview中的每个下一个图像,我们需要大约300-500kbytes的内存=下载的字节(大约60-100kb)+位图(140kb)+网络工作人员+查看人员。 我在Android Studio中使用内存分配跟踪确认了它。

所以在堆增长之前,一些内存和没有引用的对象被收集(释放270K,释放119K,......),似乎只有Bitmap保留。

所以我的问题:

为什么即使有大约3000千字节的当前活动堆,Android也无法分配140甚至500千字节?

可以是特定设备或Android版本的问题吗?

1 个答案:

答案 0 :(得分:1)

  

每个解码图像大约为140-150千字节

对于ListView行而言相当大,因为这相当于大约390x390的方形图像。

  

为什么即使有大约3000千字节的当前活动堆,Android也无法分配140甚至500千字节?

因为&#34; 3000千字节没有当前的活堆&#34;在Android中是一个毫无意义的概念。您正在浏览GC_FOR_ALLOC,因为没有足够大的可用内存块来满足您的请求。

引用myself,使用简单的可编辑性编辑:

  

在Java中,在JVM上,如果没有足够大的单块内存,那就意味着我们   实际上是内存不足(无论如何都是这个请求)。

     

然而,JVM有一件事就是Dalvik VM没有:压缩垃圾收集器。

     

当我们用支持垃圾收集的运行时运行的语言编写程序时,   我们创建了一堆对象,然后我们发布了这些对象的一些子集。另一个   我们坚持了一段时间,因为我们仍在使用它们。例如,在Android中   我们的Application,我们的ContentProvider,我们的Thread,我们自己的静态数据成员,   在很多情况下,在此过程中,等等都将存在相当长的一段时间。   他们可以达到的任何东西也不会被垃圾收集。所以,我们分配一堆   记忆并在我们的应用程序运行时释放一些内存。

     

使用压缩垃圾收集器,长寿命对象在内存中滑动,   允许释放的内存块合并。网是所有免费堆   空间应作为一个连续的块提供,有资格分配。

     

(细节比这更复杂,但这是Stack Overflow的答案,而不是论文)

     

使用非压缩垃圾收集器,内存中没有任何东西滑动。我们结束了   堆碎片,曾经是一个原始的16MB(或32MB,或48MB,或其他)   堆现在是一堆带有散布空闲内存的对象。即使我们可能   如果该空闲堆空间的最大单个块是唯一的,则具有10MB的可用堆空间   1MB,我们不能分配8MB Bitmap,因为没有足够大的空闲块。

     

Dalvik VM有一个非压缩的垃圾收集器。

请注意,ART(Android 5.0+)有一个压缩的垃圾收集器,但仅限于应用程序在后台。