Hi Romain, Thanks a lot for your answer: this should definitely help fix the issue! In fact, I wouldn't be surprised if a lot of posts regarding OutOfMemory issues are caused by the same problem.
However, I think many hours of bug hunting could have been prevented if this 'recycler' point was mentioned in the API docs for Adapter. My own thinking was that "convertView" was basically the View that was previously generated (for the item above the current one in the list), and if you wouldn't use it, it would be garbage collected. Take the following from getView: "convertView - The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view." It actually talks about "this method can create a new view", but to me it's not clear that a reference to each returned View is kept somewhere in the ListView. How could I have known this? You may have written part of this code, so it's probably very obvious to you, but to the outside developer, it's not. The point about how you MUST reuse the convertView should be stressed much more clearly in the API docs, in my opinion. As well as the point about the recycler. Alternatively, maybe the Adapter implementation could be changed so that it always only keeps one reference of a particular type of View. Why should it keep multiple references to the same View type, if it's only possible to provide a single one as convertView? Either way, I'm very happy to finally understand the inner workings of the Adapter, and it will help create more robust code. Kind regards, - Niek <i posted this msg in Issue 2391 as well: my original msg here took over 24 hours to get posted due to moderation> On Apr 9, 8:44 pm, Romain Guy <romain...@google.com> wrote: > There is no memory leak in LayoutInflater. While this is never a > proof, it's something we never encountered in > any of the apps we wrote. Also, the Android team works very hard to > plug all the memory leaks we can find > and when we tell developers to use less memory it's when we're pretty > sure that the APIs that seem to be > causing the memory leak are not responsible. > > For instance, in your case you are basically saying that if you > inflate views until you run out of memory, you > run out of memory. Every View created by the adapter is kept by the > ListView in a 'recycler'. That recycler is > used to provide the adapter with a convertView whenever possible. That > means you MUST reuse the > convertView. > > If you need views of different types in the list, just use the > appropriate APIs: Adapter.getViewTypeCount() and > Adapter.getItemViewType(int position) > (seehttp://d.android.com/reference/android/widget/Adapter.html). If > you implement these methods correctly, ListView will manage several > recyclers and always give you back the > correct convertView. > > On Wed, Apr 8, 2009 at 6:14 AM, Niek <niekvansuchte...@gmail.com> wrote: > > > Hi guys, > > > I've read several posts from developers having OutOfMemory issues, and > > a lot of them seem to be related to lists. I'm having a similar issue, > > and the root of the problem seems to be a memory leak in the inflation > > process. > > > The problem is particularly tricky to track down, because as of yet it > > seems impossible to get a view of part of the heap (where the bitmaps > > reside, and possibly other objects), as also mentioned by Ward and > > others. > > > I created a small demo, so hopefully some Google engineers (Romain, > > Dianne) can look at this, and either point out to me what I'm doing > > wrong, or fix a possible memory leak in the inflation process in the > > Android framework. I'm sure a lot of people would be very thankful if > > this issue got resolved, as it often results in sudden crashes of the > > app, without a clear reason. I must say it's disappointing to read the > > standard: "use less memory" reply from Google to a lot of these posts, > > as it seems to be worthy of further investigation. > > > Here's the demo, and the resulting logcat log with some peculiarities > > contained within. > > >http://www.coffeebreakmedia.com/android_heap_issue.zip > > > A small explanation: it's a very simple list implementation with a > > ListAdapter. It works fine if the list rows are inflated just once (by > > re-using the convertView), but I purposely commented out two lines of > > code: > > > // if(convertView == null) { > > convertView = inflater.inflate(R.layout.list_row, > > parent, false); > > // } > > > This is to ensure that for each row, the XML is inflated again. In > > this demo, this would be completely unnecessary and a big waste, but > > in a real life a similar scenario happens when you have a list with a > > few different types of rows (e.g., a different xml is used for the > > header of a set of items, which use their own xml). In that case, > > sometimes the convertView will be of the wrong type, in which case you > > have to inflate another one. Obviously, this would then happen less > > often than in this demo, but this only postpones the issue: eventually > > you'll run into the same problem as is demonstrated here. > > > To test the demo, simply open the project in Eclipse (you can use the > > emulator, but it also happens on the G1), and follow these > > instructions: > > > 1. Completely scroll down the list as fast as you can (all the way to > > Item 199), and then back up again. > > 2. Keep doing this until you scrolled down & up about 5 times, while > > watching the LogCat. > > > Eventually, you'll start getting errors such as these: > > > 04-08 12:15:03.380: ERROR/dalvikvm-heap(345): 13824-byte external > > allocation too large for this process. > > 04-08 12:15:03.380: ERROR/(345): VM won't let us allocate 13824 bytes > > > Keep scrolling! And you'll see this after a few more ups & downs: > > > 04-08 12:16:48.589: DEBUG/dalvikvm(345): GC freed 0 objects / 0 bytes > > in 169ms > > 04-08 12:16:48.589: INFO/dalvikvm-heap(345): Clamp target GC heap from > > 16.003MB to 16.000MB > > 04-08 12:16:48.589: INFO/dalvikvm-heap(345): Grow heap (frag case) to > > 16.000MB for 24-byte allocation > > 04-08 12:16:48.810: INFO/dalvikvm-heap(345): Clamp target GC heap from > > 18.003MB to 16.000MB > > > Apparently, the 16MB heap is used completely at this point, which > > seems rather wasteful considering the simplicity of the application in > > question. > > > After still more scrolling, you'll get errors such as this: > > > 04-08 12:17:01.700: ERROR/dalvikvm-heap(345): Out of memory on a 708- > > byte allocation. > > 04-08 12:17:01.700: INFO/dalvikvm(345): "main" prio=5 tid=3 RUNNABLE > > 04-08 12:17:01.700: INFO/dalvikvm(345): | group="main" sCount=0 > > dsCount=0 s=0 obj=0x400103e8 > > 04-08 12:17:01.700: INFO/dalvikvm(345): | sysTid=345 nice=0 > > sched=0/0 handle=-1093522276 > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > java.lang.AbstractStringBuilder.enlargeBuffer > > (AbstractStringBuilder.java:~100) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java: > > 140) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > java.lang.StringBuffer.append(StringBuffer.java:257) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at java.io.StringWriter.write > > (StringWriter.java:128) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > java.io.PrintWriter.doWrite(PrintWriter.java:659) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at java.io.PrintWriter.write > > (PrintWriter.java:640) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at java.io.PrintWriter.write > > (PrintWriter.java:624) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at java.io.PrintWriter.write > > (PrintWriter.java:677) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at java.io.PrintWriter.print > > (PrintWriter.java:471) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > java.io.PrintWriter.println(PrintWriter.java:589) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > java.lang.Throwable.printStackTrace(Throwable.java:267) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > android.util.Log.getStackTraceString(Log.java:234) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > com.android.internal.os.RuntimeInit.crash(RuntimeInit.java:278) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException > > (RuntimeInit.java:75) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:853) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:850) > > 04-08 12:17:01.700: INFO/dalvikvm(345): at > > dalvik.system.NativeStart.main(Native Method) > > > and this: > > > 04-08 12:18:04.530: ERROR/dalvikvm-heap(345): Out of memory on a 892- > > byte allocation. > > 04-08 12:18:04.540: INFO/dalvikvm(345): "main" prio=5 tid=3 RUNNABLE > > 04-08 12:18:04.540: INFO/dalvikvm(345): | group="main" sCount=0 > > dsCount=0 s=0 obj=0x400103e8 > > 04-08 12:18:04.540: INFO/dalvikvm(345): | sysTid=345 nice=0 > > sched=0/0 handle=-1093522276 > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > java.lang.AbstractStringBuilder.enlargeBuffer > > (AbstractStringBuilder.java:~100) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java: > > 140) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > java.lang.StringBuffer.append(StringBuffer.java:257) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at java.io.StringWriter.write > > (StringWriter.java:128) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > java.io.PrintWriter.doWrite(PrintWriter.java:659) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at java.io.PrintWriter.write > > (PrintWriter.java:640) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at java.io.PrintWriter.write > > (PrintWriter.java:624) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at java.io.PrintWriter.write > > (PrintWriter.java:677) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at java.io.PrintWriter.print > > (PrintWriter.java:471) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > java.io.PrintWriter.println(PrintWriter.java:589) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > java.lang.Throwable.printStackTrace(Throwable.java:267) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > android.util.Log.getStackTraceString(Log.java:234) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > com.android.internal.os.RuntimeInit.crash(RuntimeInit.java:286) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException > > (RuntimeInit.java:75) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:853) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:850) > > 04-08 12:18:04.540: INFO/dalvikvm(345): at > > dalvik.system.NativeStart.main(Native Method) > > > Until eventually, the story ends rather sadly: > > > 04-08 12:18:11.882: INFO/WindowManager(47): WIN DEATH: Window{43471f70 > > com.test/com.test.ListTestActivity} > > 04-08 12:18:11.882: INFO/ActivityManager(47): Process com.test (pid > > 345) has died. > > > And the app simply crashes. By the way, the same behavior will occur > > if you remove the list icon. In a real app scenario, this also seems > > to result in OutOfMemoryErrors such as these: > > > 03-26 14:24:14.974: ERROR/dalvikvm-heap(381): 64000-byte external > > allocation too large for this process. > > 03-26 14:24:14.984: ERROR/(381): VM won't let us allocate 64000 bytes > > 03-26 14:24:14.994: DEBUG/AndroidRuntime(381): Shutting down VM > > 03-26 14:24:14.994: WARN/dalvikvm(381): threadid=3: thread > > ... > > read more » --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to android-developers@googlegroups.com To unsubscribe from this group, send email to android-developers-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-developers?hl=en -~----------~----~----~----~------~----~------~--~---