【问题标题】:Android GridView garbage collecting (GC_EXTERNAL_ALLOC) <1K overzealously, causing very choppy UIAndroid GridView 垃圾收集 (GC_EXTERNAL_ALLOC) <1K 过热,导致 UI 非常不稳定
【发布时间】:2011-12-15 09:40:10
【问题描述】:

我已经看了很长时间,最后决定发布 - 我的 2xN GridView,它由具有单个图像和一段文本的单元格组成,很多时候非常不稳定(但有时非常流畅)。在检查 logcat 输出后,一旦开始滚动,我就会看到类似这样的内容(列表中只有 12 项):

10-25 17:28:40.420: D/dalvikvm(12159): GC_EXTERNAL_ALLOC freed 6K, 47% free 3383K/6279K, external 2044K/2161K, paused 38ms
10-25 17:28:40.510: D/dalvikvm(12159): GC_EXTERNAL_ALLOC freed <1K, 47% free 3383K/6279K, external 2044K/2161K, paused 36ms
10-25 17:28:40.600: D/dalvikvm(12159): GC_EXTERNAL_ALLOC freed <1K, 47% free 3383K/6279K, external 2044K/2161K, paused 40ms
10-25 17:28:41.805: D/dalvikvm(12159): GC_EXTERNAL_ALLOC freed 1K, 47% free 3383K/6279K, external 2044K/2161K, paused 34ms
10-25 17:28:41.840: D/dalvikvm(12159): GC_EXTERNAL_ALLOC freed <1K, 47% free 3383K/6279K, external 2044K/2161K, paused 25ms
10-25 17:28:41.880: D/dalvikvm(12159): GC_EXTERNAL_ALLOC freed <1K, 47% free 3383K/6279K, external 2044K/2161K, paused 25ms
10-25 17:28:41.910: D/dalvikvm(12159): GC_EXTERNAL_ALLOC freed <1K, 47% free 3383K/6279K, external 2044K/2161K, paused 20ms
10-25 17:28:41.940: D/dalvikvm(12159): GC_EXTERNAL_ALLOC freed <1K, 47% free 3383K/6279K, external 2044K/2161K, paused 18ms

这只是轻弹到列表底部并备份。非常波涛汹涌。如果我继续上下滚动,GC 可能会继续滚动 5-6 次,然后停止。但是当我按下 Menu 时,它会弹出一个 2 项菜单或切换活动并返回,GC 也会返回。

我关闭了图像的位图分配 - 同样的问题。我的单元格基本上是空的,但 GC 仍然会发生。

我联系了 Romain Guy,他说我应该尝试分配跟踪。我运行跟踪并轻弹,但在我自己的代码中没有看到分配。我确实看到了分配,然后是调用 com.android.internal.os.BinderInternal$GcWatcher 在 finalize 中分配,与 logcat 中的 GC 行数匹配。这是整个分配跟踪器转储(或更容易解析的as a picture):

1   24  org.apache.harmony.dalvik.ddmc.Chunk    5   org.apache.harmony.dalvik.ddmc.DdmServer    dispatch    
2   12  java.lang.Integer   5   java.lang.Integer   valueOf 
3   24  byte[]  5   dalvik.system.NativeStart   run 
4   20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
5   20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
6   20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
7   20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
8   20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
9   20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
10  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
11  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
12  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
13  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
14  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
15  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
16  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
17  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
18  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
19  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
20  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
21  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
22  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
23  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
24  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
25  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
26  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
27  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
28  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
29  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
30  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
31  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
32  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
33  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
34  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
35  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
36  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
37  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
38  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
39  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
40  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
41  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
42  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
43  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
44  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
45  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
46  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
47  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
48  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
49  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
50  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
51  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
52  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
53  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
54  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
55  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
56  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
57  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
58  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
59  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
60  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
61  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
62  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
63  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
64  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
65  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
66  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
67  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
68  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
69  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
70  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
71  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
72  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
73  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
74  24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
75  36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
76  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
77  24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
78  36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
79  24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
80  36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
81  8   com.android.internal.os.BinderInternal$GcWatcher    2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
82  24  java.lang.ref.WeakReference 2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
83  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
84  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
85  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
86  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
87  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
88  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
89  24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
90  36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
91  24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
92  36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
93  20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
94  24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
95  36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
96  8   com.android.internal.os.BinderInternal$GcWatcher    2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
97  24  java.lang.ref.WeakReference 2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
98  24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
99  36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
100 20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
101 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
102 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
103 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
104 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
105 8   com.android.internal.os.BinderInternal$GcWatcher    2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
106 24  java.lang.ref.WeakReference 2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
107 20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
108 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
109 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
110 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
111 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
112 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
113 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
114 8   com.android.internal.os.BinderInternal$GcWatcher    2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
115 24  java.lang.ref.WeakReference 2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
116 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
117 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
118 20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
119 60  com.carrieriq.iqagent.client.metrics.ui.UI11    1   android.view.ViewRoot   submitPointerMetrics    
120 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
121 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
122 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
123 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
124 8   com.android.internal.os.BinderInternal$GcWatcher    2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
125 24  java.lang.ref.WeakReference 2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
126 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
127 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
128 20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
129 60  com.carrieriq.iqagent.client.metrics.ui.UI11    1   android.view.ViewRoot   submitPointerMetrics    
130 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
131 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
132 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
133 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
134 8   com.android.internal.os.BinderInternal$GcWatcher    2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
135 24  java.lang.ref.WeakReference 2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
136 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
137 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
138 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
139 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
140 20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
141 60  com.carrieriq.iqagent.client.metrics.ui.UI11    1   android.view.ViewRoot   submitPointerMetrics    
142 60  com.carrieriq.iqagent.client.metrics.ui.UI11    1   android.view.ViewRoot   submitPointerMetrics    
143 60  com.carrieriq.iqagent.client.metrics.ui.UI11    1   android.view.ViewRoot   submitPointerMetrics    
144 20  java.util.ArrayList 19  android.os.MessageQueue <init>  
145 36  android.os.MessageQueue 19  android.os.Looper   <init>  
146 24  android.os.Looper   19  android.os.Looper   prepare 
147 144 java.lang.Object[]  19  java.lang.ThreadLocal$Values    initializeTable 
148 32  java.lang.ThreadLocal$Values    19  java.lang.ThreadLocal   initializeValues    
149 16  java.lang.VMThread  1   java.lang.VMThread  create  
150 40  java.util.WeakHashMap$Entry 1   java.util.WeakHashMap   put 
151 16  java.security.ProtectionDomain[]    1   java.security.AccessControlContext  <init>  
152 20  java.security.AccessControlContext  1   java.security.AccessController  getContext  
153 16  java.security.ProtectionDomain[]    1   java.security.AccessController  getStackDomains 
154 24  java.lang.String    1   java.lang.AbstractStringBuilder toString    
155 48  char[]  1   java.lang.AbstractStringBuilder <init>  
156 20  java.lang.StringBuilder 1   java.lang.Thread    create  
157 16  android.view.ViewRoot$2 1   android.view.ViewRoot   handleLongPress 
158 80  java.lang.Thread    1   android.view.ViewRoot   handleLongPress 
159 60  com.carrieriq.iqagent.client.metrics.ui.UI11    1   android.view.ViewRoot   submitPointerMetrics    
160 24  org.apache.harmony.dalvik.ddmc.Chunk    5   android.ddm.DdmHandleHeap   handleREAQ  
161 17  byte[]  5   android.ddm.DdmHandleHeap   handleREAQ  
162 24  org.apache.harmony.dalvik.ddmc.Chunk    5   org.apache.harmony.dalvik.ddmc.DdmServer    dispatch    
163 12  java.lang.Integer   5   java.lang.Integer   valueOf 
164 24  byte[]  5   dalvik.system.NativeStart   run 

如您所见,直接在 GC 之前和在每次 GC 之间发生的事件大致如下:

107 20  java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl  1   java.util.concurrent.CopyOnWriteArrayList   iterator    
108 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
109 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
110 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
111 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
112 24  java.lang.ref.SoftReference 1   android.view.View   buildDrawingCache   
113 36  android.graphics.Bitmap 1   android.graphics.Bitmap nativeCreate    
114 8   com.android.internal.os.BinderInternal$GcWatcher    2   com.android.internal.os.BinderInternal$GcWatcher    finalize    
115 24  java.lang.ref.WeakReference 2   com.android.internal.os.BinderInternal$GcWatcher    finalize    

我真的希望分配跟踪器允许我导出带有单独堆栈跟踪的整个转储,但它没有,所以我将在此处粘贴一些堆栈跟踪,其中大部分与绘图有关:

android.graphics.Bitmap:

android.graphics.Bitmap nativeCreate    Bitmap.java -2  true    
android.graphics.Bitmap createBitmap    Bitmap.java 477 false   
android.view.View   buildDrawingCache   View.java   6716    false   
android.view.View   getDrawingCache View.java   6567    false   
android.view.ViewGroup  drawChild   ViewGroup.java  1571    false   
android.view.ViewGroup  dispatchDraw    ViewGroup.java  1373    false   
android.widget.AbsListView  dispatchDraw    AbsListView.java    1627    false   
android.widget.GridView dispatchDraw    GridView.java   1943    false   
android.view.View   draw    View.java   7022    false   
android.widget.AbsListView  draw    AbsListView.java    3005    false   
android.view.ViewGroup  drawChild   ViewGroup.java  1646    false   
android.view.ViewGroup  dispatchDraw    ViewGroup.java  1373    false   
android.view.View   draw    View.java   7022    false   
android.view.ViewGroup  drawChild   ViewGroup.java  1646    false   
android.view.ViewGroup  dispatchDraw    ViewGroup.java  1373    false   
android.view.ViewGroup  drawChild   ViewGroup.java  1644    false   

java.util.concurrent.CopyOnWriteArrayList:

java.util.concurrent.CopyOnWriteArrayList   iterator    CopyOnWriteArrayList.java   332 false   
android.view.ViewTreeObserver   dispatchOnPreDraw   ViewTreeObserver.java   570 false   
android.view.ViewRoot   performTraversals   ViewRoot.java   1293    false   
android.view.ViewRoot   handleMessage   ViewRoot.java   1899    false   
android.os.Handler  dispatchMessage Handler.java    99  false   
android.os.Looper   loop    Looper.java 130 false   
android.app.ActivityThread  main    ActivityThread.java 3691    false   
java.lang.reflect.Method    invokeNative    Method.java -2  true    
java.lang.reflect.Method    invoke  Method.java 507 false   
com.android.internal.os.ZygoteInit$MethodAndArgsCaller  run ZygoteInit.java 907 false   
com.android.internal.os.ZygoteInit  main    ZygoteInit.java 665 false   
dalvik.system.NativeStart   main    NativeStart.java    -2  true    

这是我的 GridView 容器 XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >
  <LinearLayout
    android:id="@+id/scroll_items_holder"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:background="@drawable/app_bg"
    android:orientation="vertical" >
    <LinearLayout
      android:id="@+id/buttonsLayout"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center" >
    </LinearLayout>
    <GridView
      android:id="@+id/gridview"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:columnWidth="150dp"
      android:gravity="right"
      android:horizontalSpacing="0dp"
      android:listSelector="@null"
      android:numColumns="auto_fit"
      android:paddingLeft="5dp"
      android:paddingRight="5dp"
      android:stretchMode="columnWidth"
      android:verticalSpacing="10dp" />
  </LinearLayout>
  <include layout="@layout/menu_bar_inc" />
</LinearLayout>

每个 GridView 单元格的 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/card"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical" >
  <ImageView
    android:id="@+id/thumbnail"
    android:layout_width="fill_parent"
    android:layout_height="120dp"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="5dp"
    android:scaleType="centerCrop" />
  <TextView
    android:id="@+id/show_name"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:ellipsize="marquee"
    android:maxLines="1"
    android:textColor="@color/white"
    android:textStyle="bold" />
</LinearLayout>

适配器,大部分都被注释掉了:

package com.tunerfish.tunerfish.adapters;

import java.util.ArrayList;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.tunerfish.tunerfish.core.TfHomeActivity;
import com.tunerfish.tunerfish.databasemanager.dataitem.EntityDataItem;
import com.tunerfish.tunerfish.ui.R;

public class TrendingGalleryAdapter extends BaseAdapter {

  // structure for dumb view holders
  public static class ViewHolder {
    public TextView showName;
    // public ImageViewWithLoader thumbnail;
  }

  // structure for actual data behind the ListView
  public static class EntityData {
    public EntityDataItem entityDataItem;
  }

  public final ArrayList<EntityData> mEntityDataList;

  private final LayoutInflater mInflater;

  public TrendingGalleryAdapter(TfHomeActivity context, ArrayList<EntityData> entityData) {
    mContext = context;
    mInflater = LayoutInflater.from(context);
    mEntityDataList = entityData;
  }

  @Override public int getCount() {
    return mEntityDataList.size();
  }

  @Override public EntityData getItem(int position) {
    return mEntityDataList.get(position);
  }

  @Override public long getItemId(int position) {
    return position;
  }

  private final TfHomeActivity mContext;

  @Override public View getView(final int position, View inView, ViewGroup parent) {
    ViewHolder holder;

    if (inView == null) {
      holder = new ViewHolder();
      inView = mInflater.inflate(R.layout.trending_item_mod, null);
      holder.showName = (TextView) inView.findViewById(R.id.show_name);
      // holder.thumbnail = (ImageViewWithLoader) inView.findViewById(R.id.thumbnail);

      inView.setTag(holder);
    } else {
      holder = (ViewHolder) inView.getTag();
    }

    // reset some stuff
    // holder.thumbnail.getImageView().setImageBitmap(null);

    // holder.showName.setText(getItem(position).entityDataItem.getTitle());

    // deal with thumbnails
    String thumbnailUrl = getItem(position).entityDataItem.getTrendingThumbnail();
    // mContext.sendImgDownloadRequest(thumbnailUrl, holder.thumbnail.getImageView(), R.drawable.tunerfish_details_logo2);

    return inView;
  }
}

所以,这个问题可能看起来很长,但我想包含尽可能多的信息。我发现了一个可能相关的 ListView 问题Lots of garbage collection in a listview,但不幸的是它似乎不适用于 GridViews。

此外,似乎并非只有我一个人遇到这个问题 - 我的一个朋友联系我询问他的应用程序中完全相同的问题,完全独立。

我的测试设备是运行 CM 7.1 的 OG Droid 和运行 Gingerbread 的 Epic 4G Touch。

那么这是一个框架错误吗?难道我做错了什么?我是不是没有包含某个参数?

谢谢。

【问题讨论】:

  • 您确定在适配器类的 getView 方法中使用 convertView 参数吗?
  • 代码就在上面——你可以自己看。我相信 getView 已正确实施,但与问题无关。请参阅下面的答案。
  • 糟糕。对不起。我应该仔细阅读。我的错。
  • Ummm...每次调用getView()sendImgDownloadRequest)时,您是否都在下载图像?如果是这样,这就是你的ListView 不稳定的原因!您正在 UI 线程中执行网络请求!使用异步任务并缓存图像。
  • @dmon 该代码确定图像是否在缓存中,并在这种情况下使用缓存。不是每次都下载。此外,我放置了一个滚动监听器并保留所有下载请求,直到滚动停止以进一步优化滚动。

标签: android gridview garbage-collection scroll


【解决方案1】:

在随机尝试了更多东西之后,我相信我能够通过在 XML 中将 GridView 的 scrollingCache 设置为 false 来解决这个问题。它现在非常光滑。

http://developer.android.com/reference/android/widget/AbsListView.html#attr_android:scrollingCache

因此,应该使 GridView 使用更多内存并更快地从缓存中提取的设置实际上由于 GC 导致其不稳定而导致相反的结果。关闭缓存使用更少的内存并且不再不稳定。

这在我的书中是双赢的,我希望它对未来的人有所帮助(ಠ_ಠ Google)。

编辑:刚刚在性能不错的 ListView 上尝试过,它偶尔会调用 GC_EXTERNAL_ALLOC 来释放少量内存。从 ListView 中删除它完全摆脱了许多微小的 GC_EXTERNAL_ALLOC 调用,只剩下偶尔较大的 GC_CONCURRENT 调用。现在一个表现不错的 ListView 就是一个表现出色的 ListView。所以scrollingCache 似乎是在任何列表中都应该避免的东西,并且不应该在默认情况下启用 IMO。

【讨论】:

  • 请不要在没有真正理解可能发生的情况下做出这样的通用断言。如果 scrollingCache 是一个普遍的问题,我们不会在默认情况下保留它。您的特定问题可能是由于您的列表项大小不同。每当调整缓存视图的大小时,都需要重新创建其位图缓存,这不是常见的情况。
  • 我的 GridView 大小没有变化 - 它是单行文本 + 具有预定义高度的单个图像。至于 ListViews,我认为 ListView 中不同高度的单元格很常见,大多数情况下是因为标题可能会溢出超过 1 行。
  • 不管怎样,我不是唯一一个遇到这个问题的人,我很想在指南和 API 文档中看到一些解释、讨论和建议。这里有一个严重的性能影响,即使不是在所有情况下都会发生,但让开发人员知道这可能是问题所在也没有什么坏处。
  • 我会在这里添加我的声音。我在 Android 2.3.4 上对此进行了测试,得出了与 Artem 相同的结果。当在 gridview 或 listview 上启用滚动缓存时,会有很多垃圾收集器活动并且性能不稳定。禁用时,GC 会安静下来,并且性能很流畅。
  • @RomainGuy 你有没有得到任何地方?
【解决方案2】:

这也是 ListViews 的一个问题,频繁的 stop-the-world 垃圾回收会导致终端用户体验不佳,并导致用户将 UI 性能波动归咎于 Android。不过同样的方法也可以解决这个问题,将scrollingCache设置为false。

【讨论】:

    【解决方案3】:

    在 ListActivity 中使用带有自定义 2 行 ListView 布局的 SimpleCursorAdapter,没有图像只是文本,我有 CacheColorHint - #00000000。 在我开始之前我会说一个快速修复是删除 cachecolorhint 但我需要它所以它不是对 GC 的修复所以....

    我现在和过去都遇到过同样的问题,但是这会引发一个曲线球......我有两个应用程序,它们本质上是彼此的镜像。一个运行得很好,在 logcat 中没有猖獗的垃圾收集,它滚动得很漂亮,另一个运行得不太好,什么也没有,没有复制和粘贴代码可以从一个到另一个修复它。

    ALSO!...有时在应用程序中运行得不太好,当我从查询中使用列表并为列表视图使用稍微不同的布局时,我可以让它工作。不过不要妄下结论,因为如果我离开并返回,在自定义 2 行列表项布局上使用简单光标适配器的相同排序查询将再次导致 GC。换句话说,有时它会简单地正常工作,而有时则不会。请注意,我将“scrollingCache”作为两个应用程序的默认设置,正如我所说,它们是彼此的副本。

    不久前我遇到了这个问题并且能够以某种方式解决它,它与 ScrollingCache 无关。相反,它与我针对某些旧版本的 Android 编译的构建有关(我认为)我的记忆不是 100% 确定这一点,但我发誓修复与构建/编译器问题有关。如果我记得修复它的内容,我会发布一些东西。我使用环绕,所以我正在寻找变化。 我希望这是有道理的

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-21
      • 2012-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多