在我的项目中,我有最简单的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版本的问题吗?
答案 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+)有一个压缩的垃圾收集器,但仅限于应用程序在后台。