[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
On Tue, May 26, 2009 at 12:47 AM, Robert Green rbgrn@gmail.com wrote: That is SO MUCH more code than I ever wanted there but it's ridiculously more efficient than it was before so I'm going to call it good and move on. It looks like a lot of your code comes from C code that had to run very very fast on very old CPUs that didn't have fast multiplication instructions. Unfortunately, they risk to be slower than necessary on Dalvik. May I suggest the much simpler alternative: public static void getChars(int i, int index, char[] buf) { if (i == Integer.MIN_VALUE) { System.arraycopy(-2147483648.toCharArray(), 0, buf, 0, buf.length); } int q, r; // assumes 'index' accounts for the sign if present int charPos = index; char sign = 0; if (i 0) { sign = '-'; i = -i; index -= 1; } while (index 0) { q = i / 10; r = i - q*10; buf[--charPos] = '0' + r; i = q; index--; } if (sign != 0) { buf[--charPos] = sign; } } Thanks for the help everyone! On May 25, 5:19 pm, Jason Proctor ja...@particularplace.com wrote: i'll suggest this again :-) when the score changes, convert to a string then, save it away, and draw that each frame. at least then, you're only doing an allocation when it changes. good enough? My new method doesn't have problems with concatenating but no solution so far has gotten around converting an integer into a String or CharSequence. Any time you put an integer where a String should be, java automatically uses Integer.toString(i) to build a String out of it which allocates a char[] and also makes a new String. So, besides ripping out stringSize and getChars from integer and holding my own char[] for the converted int, is there a clean way to handle that without new allocations? On May 25, 4:29 pm, Jason Proctor ja...@particularplace.com wrote: i think Mark is saying that you could redraw the score separately from the label, potentially saving an implicit new StringBuffer (stuff).toString () ? if score is a number, then it will need to make a new String anyway. but you could cache the string of the score until the score changes, so that drawing the score becomes drawing to strings as opposed to going through StringBuffer. hth It's a surface view so the whole scene must be rendered every frame. I could put it on the background I suppose but it's simple enough to just redraw the text. On May 25, 4:10 pm, Mark Murphy mmur...@commonsware.com wrote: Robert Green wrote: I said StringBuffer but I meant Implied StringBuffer, you know: canvas.drawText(score + POINTS_LABEL, x, y, paint); Why redraw POINTS_LABEL every time? Can't you rework your scoreboard to only draw that once? -- Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy Android App Developer Training: http://commonsware.com/training.html -- jason.software.particle -- jason.software.particle --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
On Mon, Jun 1, 2009 at 9:20 PM, Robert Green rbgrn@gmail.com wrote: Dan, thanks for clearing that up. Glad to be of service. It's always nice to have *the* guy who wrote the VM (emphasis mine) I definitely can't take all that credit, not being surrounded[*] as I am by the *many* fine folks who also worked and continue to work on it. Main designer and tech lead? Sure, but my fingers would be bloody pulpy stumps if I wrote it all. -dan [*] literally --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
David, That's not my code - that was a package method ripped from java.lang.Integer. I had to copy/post it because it's needed to make write an int's String's char[] directly without instantiating anything. On Jun 2, 7:27 am, David Turner di...@android.com wrote: On Tue, May 26, 2009 at 12:47 AM, Robert Green rbgrn@gmail.com wrote: That is SO MUCH more code than I ever wanted there but it's ridiculously more efficient than it was before so I'm going to call it good and move on. It looks like a lot of your code comes from C code that had to run very very fast on very old CPUs that didn't have fast multiplication instructions. Unfortunately, they risk to be slower than necessary on Dalvik. May I suggest the much simpler alternative: public static void getChars(int i, int index, char[] buf) { if (i == Integer.MIN_VALUE) { System.arraycopy(-2147483648.toCharArray(), 0, buf, 0, buf.length); } int q, r; // assumes 'index' accounts for the sign if present int charPos = index; char sign = 0; if (i 0) { sign = '-'; i = -i; index -= 1; } while (index 0) { q = i / 10; r = i - q*10; buf[--charPos] = '0' + r; i = q; index--; } if (sign != 0) { buf[--charPos] = sign; } } Thanks for the help everyone! On May 25, 5:19 pm, Jason Proctor ja...@particularplace.com wrote: i'll suggest this again :-) when the score changes, convert to a string then, save it away, and draw that each frame. at least then, you're only doing an allocation when it changes. good enough? My new method doesn't have problems with concatenating but no solution so far has gotten around converting an integer into a String or CharSequence. Any time you put an integer where a String should be, java automatically uses Integer.toString(i) to build a String out of it which allocates a char[] and also makes a new String. So, besides ripping out stringSize and getChars from integer and holding my own char[] for the converted int, is there a clean way to handle that without new allocations? On May 25, 4:29 pm, Jason Proctor ja...@particularplace.com wrote: i think Mark is saying that you could redraw the score separately from the label, potentially saving an implicit new StringBuffer (stuff).toString () ? if score is a number, then it will need to make a new String anyway. but you could cache the string of the score until the score changes, so that drawing the score becomes drawing to strings as opposed to going through StringBuffer. hth It's a surface view so the whole scene must be rendered every frame. I could put it on the background I suppose but it's simple enough to just redraw the text. On May 25, 4:10 pm, Mark Murphy mmur...@commonsware.com wrote: Robert Green wrote: I said StringBuffer but I meant Implied StringBuffer, you know: canvas.drawText(score + POINTS_LABEL, x, y, paint); Why redraw POINTS_LABEL every time? Can't you rework your scoreboard to only draw that once? -- Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy Android App Developer Training: http://commonsware.com/training.html -- jason.software.particle -- jason.software.particle --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
On Tue, Jun 2, 2009 at 11:27 PM, Robert Green rbgrn@gmail.com wrote: David, That's not my code - that was a package method ripped from java.lang.Integer. I had to copy/post it because it's needed to make write an int's String's char[] directly without instantiating anything. no problem :-) I was just seeing you complaining about that much more code so I thought I could help reduce the burden. After all, if something's not broken... On Jun 2, 7:27 am, David Turner di...@android.com wrote: On Tue, May 26, 2009 at 12:47 AM, Robert Green rbgrn@gmail.com wrote: That is SO MUCH more code than I ever wanted there but it's ridiculously more efficient than it was before so I'm going to call it good and move on. It looks like a lot of your code comes from C code that had to run very very fast on very old CPUs that didn't have fast multiplication instructions. Unfortunately, they risk to be slower than necessary on Dalvik. May I suggest the much simpler alternative: public static void getChars(int i, int index, char[] buf) { if (i == Integer.MIN_VALUE) { System.arraycopy(-2147483648.toCharArray(), 0, buf, 0, buf.length); } int q, r; // assumes 'index' accounts for the sign if present int charPos = index; char sign = 0; if (i 0) { sign = '-'; i = -i; index -= 1; } while (index 0) { q = i / 10; r = i - q*10; buf[--charPos] = '0' + r; i = q; index--; } if (sign != 0) { buf[--charPos] = sign; } } Thanks for the help everyone! On May 25, 5:19 pm, Jason Proctor ja...@particularplace.com wrote: i'll suggest this again :-) when the score changes, convert to a string then, save it away, and draw that each frame. at least then, you're only doing an allocation when it changes. good enough? My new method doesn't have problems with concatenating but no solution so far has gotten around converting an integer into a String or CharSequence. Any time you put an integer where a String should be, java automatically uses Integer.toString(i) to build a String out of it which allocates a char[] and also makes a new String. So, besides ripping out stringSize and getChars from integer and holding my own char[] for the converted int, is there a clean way to handle that without new allocations? On May 25, 4:29 pm, Jason Proctor ja...@particularplace.com wrote: i think Mark is saying that you could redraw the score separately from the label, potentially saving an implicit new StringBuffer (stuff).toString () ? if score is a number, then it will need to make a new String anyway. but you could cache the string of the score until the score changes, so that drawing the score becomes drawing to strings as opposed to going through StringBuffer. hth It's a surface view so the whole scene must be rendered every frame. I could put it on the background I suppose but it's simple enough to just redraw the text. On May 25, 4:10 pm, Mark Murphy mmur...@commonsware.com wrote: Robert Green wrote: I said StringBuffer but I meant Implied StringBuffer, you know: canvas.drawText(score + POINTS_LABEL, x, y, paint); Why redraw POINTS_LABEL every time? Can't you rework your scoreboard to only draw that once? -- Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy Android App Developer Training: http://commonsware.com/training.html -- jason.software.particle -- jason.software.particle --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
On Mon, May 25, 2009 at 1:34 PM, Mark Murphy mmur...@commonsware.com wrote: 2) What about local variable arrays? Do those go in the heap (short lived, GC) or on the stack? The array is on the stack. If the array is a primitive array (int[]), that covers everything. If the array is of objects (Dog[]), the Dog instances are from the heap. Actually, all array contents live on the heap, whether the contents are primitives or objects, and a simple reference to the array will be on the stack in a local variable. For example: static void blort() { int[] arr = { 1, 2, 3 }; // here } At here, the stack frame for blort() will contain a single local variable reference for arr, which will point at a freshly-allocated array on the heap containing { 1, 2, 3 }. -dan --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
Dan, thanks for clearing that up. It's always nice to have the guy who wrote the VM step in and steer us lowly developers in the right direction :) I do have a logical question following your example, though: If a blort can snort, and a snort is a fort, are all blorts forts? On Jun 1, 7:34 pm, Dan Bornstein danf...@android.com wrote: On Mon, May 25, 2009 at 1:34 PM, Mark Murphy mmur...@commonsware.com wrote: 2) What about local variable arrays? Do those go in the heap (short lived, GC) or on the stack? The array is on the stack. If the array is a primitive array (int[]), that covers everything. If the array is of objects (Dog[]), the Dog instances are from the heap. Actually, all array contents live on the heap, whether the contents are primitives or objects, and a simple reference to the array will be on the stack in a local variable. For example: static void blort() { int[] arr = { 1, 2, 3 }; // here } At here, the stack frame for blort() will contain a single local variable reference for arr, which will point at a freshly-allocated array on the heap containing { 1, 2, 3 }. -dan --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
Have you tried using hprof/jhat ? See http://android.git.kernel.org/?p=platform/dalvik.git;a=blob_plain;f=docs/heap-profiling.html;hb=HEAD On Mon, May 25, 2009 at 1:02 PM, Robert Green rbgrn@gmail.com wrote: For the past 2 months of development, I've followed the android performance guidelines here - http://developer.android.com/guide/practices/design/performance.html - to the tee. I always cache field lookups if the field is referenced more than once in a method. I was under the assumption that since the local variable is simply a pointer to the field, that it will be on the stack and will not need to be cleaned up, just like a local variable that is a primitive. Is this correct? I'm very, very careful not to not allocate, that is, declare new objects in my main loop. With that said, I'm having a problem where I'm having about 54200 objects GCed every 55 seconds while the game is running. That translates to about 1000 objects per second, or at 60FPS (which my game runs at on the emulator), about 16 short-life objects per loop. I have absolutely scoured my code to make sure that I'm not creating anything. I must be missing something though. Here are my questions: 1) Are local variables ever affected by GC if they never call new, either explicitly or implicitly? -- I'm asking if I have a field that is private ArrayListDog dogList; and in my method, I say ArrayListDog dogList = this.dogList; - that doesn't have any impact on GC, correct? It's just a pointer on the stack, right? -- I understand that the word new doesn't need to be obvious because really any method can create something new and return it. 2) What about local variable arrays? Do those go in the heap (short lived, GC) or on the stack? 3) I did an hprof dump but it's not giving me the information I need. I'd really like to profile what is being GCed so I can figure out what's being allocated 16 times per tick. Thanks for all your help! --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
Yes, I've done an HPROF and have it open in Eclipse Memory Analyzer but it doesn't appear to be telling me what is being GCed. It looks like it's the result post-GC and is more suitable for memory usage and leak detection. I could be missing something, though. Anyone? On May 25, 3:08 pm, Marco Nelissen marc...@android.com wrote: Have you tried using hprof/jhat ? Seehttp://android.git.kernel.org/?p=platform/dalvik.git;a=blob_plain;f=d... On Mon, May 25, 2009 at 1:02 PM, Robert Green rbgrn@gmail.com wrote: For the past 2 months of development, I've followed the android performance guidelines here - http://developer.android.com/guide/practices/design/performance.html - to the tee. I always cache field lookups if the field is referenced more than once in a method. I was under the assumption that since the local variable is simply a pointer to the field, that it will be on the stack and will not need to be cleaned up, just like a local variable that is a primitive. Is this correct? I'm very, very careful not to not allocate, that is, declare new objects in my main loop. With that said, I'm having a problem where I'm having about 54200 objects GCed every 55 seconds while the game is running. That translates to about 1000 objects per second, or at 60FPS (which my game runs at on the emulator), about 16 short-life objects per loop. I have absolutely scoured my code to make sure that I'm not creating anything. I must be missing something though. Here are my questions: 1) Are local variables ever affected by GC if they never call new, either explicitly or implicitly? -- I'm asking if I have a field that is private ArrayListDog dogList; and in my method, I say ArrayListDog dogList = this.dogList; - that doesn't have any impact on GC, correct? It's just a pointer on the stack, right? -- I understand that the word new doesn't need to be obvious because really any method can create something new and return it. 2) What about local variable arrays? Do those go in the heap (short lived, GC) or on the stack? 3) I did an hprof dump but it's not giving me the information I need. I'd really like to profile what is being GCed so I can figure out what's being allocated 16 times per tick. Thanks for all your help! --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
The easiest way to find out what is being allocated is to use DDMS' allocations tracker. Launch DDMS (the *stand alone* version, not the one in Eclipse), swtich to the Allocation Track tab, select your process, hit Start tracking, play with your app, then hit Get allocations. Each allocation will be shown with the stack trace to its origin. On Mon, May 25, 2009 at 1:13 PM, Robert Green rbgrn@gmail.com wrote: Yes, I've done an HPROF and have it open in Eclipse Memory Analyzer but it doesn't appear to be telling me what is being GCed. It looks like it's the result post-GC and is more suitable for memory usage and leak detection. I could be missing something, though. Anyone? On May 25, 3:08 pm, Marco Nelissen marc...@android.com wrote: Have you tried using hprof/jhat ? Seehttp://android.git.kernel.org/?p=platform/dalvik.git;a=blob_plain;f=d... On Mon, May 25, 2009 at 1:02 PM, Robert Green rbgrn@gmail.com wrote: For the past 2 months of development, I've followed the android performance guidelines here - http://developer.android.com/guide/practices/design/performance.html - to the tee. I always cache field lookups if the field is referenced more than once in a method. I was under the assumption that since the local variable is simply a pointer to the field, that it will be on the stack and will not need to be cleaned up, just like a local variable that is a primitive. Is this correct? I'm very, very careful not to not allocate, that is, declare new objects in my main loop. With that said, I'm having a problem where I'm having about 54200 objects GCed every 55 seconds while the game is running. That translates to about 1000 objects per second, or at 60FPS (which my game runs at on the emulator), about 16 short-life objects per loop. I have absolutely scoured my code to make sure that I'm not creating anything. I must be missing something though. Here are my questions: 1) Are local variables ever affected by GC if they never call new, either explicitly or implicitly? -- I'm asking if I have a field that is private ArrayListDog dogList; and in my method, I say ArrayListDog dogList = this.dogList; - that doesn't have any impact on GC, correct? It's just a pointer on the stack, right? -- I understand that the word new doesn't need to be obvious because really any method can create something new and return it. 2) What about local variable arrays? Do those go in the heap (short lived, GC) or on the stack? 3) I did an hprof dump but it's not giving me the information I need. I'd really like to profile what is being GCed so I can figure out what's being allocated 16 times per tick. Thanks for all your help! -- Romain Guy Android framework engineer romain...@android.com Note: please don't send private questions to me, as I don't have time to provide private support. All such questions should be posted on public forums, where I and others can see and answer them --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
Robert Green wrote: 1) Are local variables ever affected by GC if they never call new, either explicitly or implicitly? -- I'm asking if I have a field that is private ArrayListDog dogList; and in my method, I say ArrayListDog dogList = this.dogList; - that doesn't have any impact on GC, correct? It's just a pointer on the stack, right? The pointer is on the stack. The ArrayList itself and its Dogs are on the heap. 2) What about local variable arrays? Do those go in the heap (short lived, GC) or on the stack? The array is on the stack. If the array is a primitive array (int[]), that covers everything. If the array is of objects (Dog[]), the Dog instances are from the heap. -- Mark Murphy (a Commons Guy) http://commonsware.com | http://twitter.com/commonsguy Need help for your Android OSS project? http://wiki.andmob.org/hado --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
Awesome! Those are the assumptions I've been working under for months and I'm so happy that I wasn't way off on one of them! I found that the standalone DDMS has an allocation tracker which is exactly the tool I needed. I immediately found my problem. Two problems: 1) I keep a running score on screen. The StringBuffer I'm using to build this is causing all types of char[] and String allocations. I'm not sure what I can do about that. 2) Calling Canvas.getMatrix() allocates a new matrix if one isn't currently being used. Interesting. I'll be able to work around that. Any ideas on what I can do about those strings? Basically I need to display Pts for the current score. On May 25, 3:34 pm, Mark Murphy mmur...@commonsware.com wrote: Robert Green wrote: 1) Are local variables ever affected by GC if they never call new, either explicitly or implicitly? -- I'm asking if I have a field that is private ArrayListDog dogList; and in my method, I say ArrayListDog dogList = this.dogList; - that doesn't have any impact on GC, correct? It's just a pointer on the stack, right? The pointer is on the stack. The ArrayList itself and its Dogs are on the heap. 2) What about local variable arrays? Do those go in the heap (short lived, GC) or on the stack? The array is on the stack. If the array is a primitive array (int[]), that covers everything. If the array is of objects (Dog[]), the Dog instances are from the heap. -- Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy Need help for your Android OSS project?http://wiki.andmob.org/hado --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
1) I keep a running score on screen. The StringBuffer I'm using to build this is causing all types of char[] and String allocations. I'm not sure what I can do about that. You can reuse a StringBuffer by deleting its content, we do that in a bunch of places in Android's source code. You can also avoid calling toString() on it or passing it to methods that treat it as a String. Calling toString() creates a copy of the buffer, which you certainly don't want. -- Romain Guy Android framework engineer romain...@android.com Note: please don't send private questions to me, as I don't have time to provide private support. All such questions should be posted on public forums, where I and others can see and answer them --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
Romain Guy wrote: You can also avoid calling toString() on it or passing it to methods that treat it as a String. Calling toString() creates a copy of the buffer, which you certainly don't want. Yeah, I'm pretty bad about that one. I keep forgetting StringBuffer/StringBuilder implement CharSequence and that lots of things take a CharSequence directly instead of a String. For example, you can hand a StringBuffer/StringBuilder to TextView#setText(). Also, allocate a big enough StringBuffer/StringBuilder at the outset, so it does not have to expand its internal buffer. Its initial capacity appears to be 16 characters, if I am reading the Android/Harmony source correctly. -- Mark Murphy (a Commons Guy) http://commonsware.com | http://twitter.com/commonsguy Need help for your Android OSS project? http://wiki.andmob.org/hado --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
I said StringBuffer but I meant Implied StringBuffer, you know: canvas.drawText(score + POINTS_LABEL, x, y, paint); I'm not sure how I can make that more efficient since drawText takes either a String or a CharacterSequence and all I can think of doing is hanging on to a char[] that is currently the correct length and drawing that. Do you have any snippets that would help me here? I'm really excited though because this is the last bit of performance optimization I'm doing before I will say that the game runs very well. BTW - I do a System.gc() before starting each level, since the levels rarely go over 15 seconds. It seems to work well to ensure that no gc occurs while the level is running but it does seem like a bit of a hack to me. I'd rather fix the allocations. Is there any downside to leaving that there for a hint at GC timing? Thanks! On May 25, 3:46 pm, Romain Guy romain...@google.com wrote: 1) I keep a running score on screen. The StringBuffer I'm using to build this is causing all types of char[] and String allocations. I'm not sure what I can do about that. You can reuse a StringBuffer by deleting its content, we do that in a bunch of places in Android's source code. You can also avoid calling toString() on it or passing it to methods that treat it as a String. Calling toString() creates a copy of the buffer, which you certainly don't want. -- Romain Guy Android framework engineer romain...@android.com Note: please don't send private questions to me, as I don't have time to provide private support. All such questions should be posted on public forums, where I and others can see and answer them --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
Robert Green wrote: I said StringBuffer but I meant Implied StringBuffer, you know: canvas.drawText(score + POINTS_LABEL, x, y, paint); Why redraw POINTS_LABEL every time? Can't you rework your scoreboard to only draw that once? -- Mark Murphy (a Commons Guy) http://commonsware.com | http://twitter.com/commonsguy Android App Developer Training: http://commonsware.com/training.html --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
It's a surface view so the whole scene must be rendered every frame. I could put it on the background I suppose but it's simple enough to just redraw the text. On May 25, 4:10 pm, Mark Murphy mmur...@commonsware.com wrote: Robert Green wrote: I said StringBuffer but I meant Implied StringBuffer, you know: canvas.drawText(score + POINTS_LABEL, x, y, paint); Why redraw POINTS_LABEL every time? Can't you rework your scoreboard to only draw that once? -- Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy Android App Developer Training:http://commonsware.com/training.html --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
couldn't you do something like: canvas.drawText(score, x, y, paint); canvas.drawText( POINTS_LABEL, x+30, y, paint); so you can rid of the string concatenation. On May 25, 11:02 pm, Robert Green rbgrn@gmail.com wrote: I said StringBuffer but I meant Implied StringBuffer, you know: canvas.drawText(score + POINTS_LABEL, x, y, paint); I'm not sure how I can make that more efficient since drawText takes either a String or a CharacterSequence and all I can think of doing is hanging on to a char[] that is currently the correct length and drawing that. Do you have any snippets that would help me here? I'm really excited though because this is the last bit of performance optimization I'm doing before I will say that the game runs very well. BTW - I do a System.gc() before starting each level, since the levels rarely go over 15 seconds. It seems to work well to ensure that no gc occurs while the level is running but it does seem like a bit of a hack to me. I'd rather fix the allocations. Is there any downside to leaving that there for a hint at GC timing? Thanks! On May 25, 3:46 pm, Romain Guy romain...@google.com wrote: 1) I keep a running score on screen. The StringBuffer I'm using to build this is causing all types of char[] and String allocations. I'm not sure what I can do about that. You can reuse a StringBuffer by deleting its content, we do that in a bunch of places in Android's source code. You can also avoid calling toString() on it or passing it to methods that treat it as a String. Calling toString() creates a copy of the buffer, which you certainly don't want. -- Romain Guy Android framework engineer romain...@android.com Note: please don't send private questions to me, as I don't have time to provide private support. All such questions should be posted on public forums, where I and others can see and answer them --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
I'm working on a small game; I decided that the best approach for my purposes was to use char[]s internally and I wrote my own simple int-char[] method. As an aside, I generate and cache a set of bitmaps for the digits 0-9 and render the score using these, rather than with the canvas drawText methods (one version of which takes a char[] which is useful in performance sensitive situations). Tom. 2009/5/25 Robert Green rbgrn@gmail.com Awesome! Those are the assumptions I've been working under for months and I'm so happy that I wasn't way off on one of them! I found that the standalone DDMS has an allocation tracker which is exactly the tool I needed. I immediately found my problem. Two problems: 1) I keep a running score on screen. The StringBuffer I'm using to build this is causing all types of char[] and String allocations. I'm not sure what I can do about that. 2) Calling Canvas.getMatrix() allocates a new matrix if one isn't currently being used. Interesting. I'll be able to work around that. Any ideas on what I can do about those strings? Basically I need to display Pts for the current score. On May 25, 3:34 pm, Mark Murphy mmur...@commonsware.com wrote: Robert Green wrote: 1) Are local variables ever affected by GC if they never call new, either explicitly or implicitly? -- I'm asking if I have a field that is private ArrayListDog dogList; and in my method, I say ArrayListDog dogList = this.dogList; - that doesn't have any impact on GC, correct? It's just a pointer on the stack, right? The pointer is on the stack. The ArrayList itself and its Dogs are on the heap. 2) What about local variable arrays? Do those go in the heap (short lived, GC) or on the stack? The array is on the stack. If the array is a primitive array (int[]), that covers everything. If the array is of objects (Dog[]), the Dog instances are from the heap. -- Mark Murphy (a Commons Guy)http://commonsware.com| http://twitter.com/commonsguy Need help for your Android OSS project?http://wiki.andmob.org/hado --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
Wow, I updated those string drawing methods to use a reusable StringBuffer and it seems to have worked! I'm so happy to have finally solved this. Here's the code I used: private StringBuffer scoreText = new StringBuffer(13); // it will never be longer than 13 chars. private void drawInfoHead(Canvas canvas) { StringBuffer scoreText = this.scoreText; scoreText.delete(0, scoreText.length()); scoreText.append(score).append(POINTS_TEXT); // the paint is right-aligned. canvas.drawText(scoreText, 0, scoreText.length(), world.width, 20, gameResources.scoreInfoTextPaint); } On May 25, 4:20 pm, Robert Green rbgrn@gmail.com wrote: It's a surface view so the whole scene must be rendered every frame. I could put it on the background I suppose but it's simple enough to just redraw the text. On May 25, 4:10 pm, Mark Murphy mmur...@commonsware.com wrote: Robert Green wrote: I said StringBuffer but I meant Implied StringBuffer, you know: canvas.drawText(score + POINTS_LABEL, x, y, paint); Why redraw POINTS_LABEL every time? Can't you rework your scoreboard to only draw that once? -- Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy Android App Developer Training:http://commonsware.com/training.html --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
Jason Proctor wrote: i think Mark is saying that you could redraw the score separately from the label, potentially saving an implicit new StringBuffer (stuff).toString () ? Uh. Yeah. That's what I meant. Honest. It's not like I've never played with Android game code and therefore did not realize you had to update the fixed text on every frame. Nope. Wasn't that. Certainly not. ;-) -- Mark Murphy (a Commons Guy) http://commonsware.com | http://twitter.com/commonsguy Android App Developer Training: http://commonsware.com/training.html --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
My new method doesn't have problems with concatenating but no solution so far has gotten around converting an integer into a String or CharSequence. Any time you put an integer where a String should be, java automatically uses Integer.toString(i) to build a String out of it which allocates a char[] and also makes a new String. So, besides ripping out stringSize and getChars from integer and holding my own char[] for the converted int, is there a clean way to handle that without new allocations? On May 25, 4:29 pm, Jason Proctor ja...@particularplace.com wrote: i think Mark is saying that you could redraw the score separately from the label, potentially saving an implicit new StringBuffer (stuff).toString () ? if score is a number, then it will need to make a new String anyway. but you could cache the string of the score until the score changes, so that drawing the score becomes drawing to strings as opposed to going through StringBuffer. hth It's a surface view so the whole scene must be rendered every frame. I could put it on the background I suppose but it's simple enough to just redraw the text. On May 25, 4:10 pm, Mark Murphy mmur...@commonsware.com wrote: Robert Green wrote: I said StringBuffer but I meant Implied StringBuffer, you know: canvas.drawText(score + POINTS_LABEL, x, y, paint); Why redraw POINTS_LABEL every time? Can't you rework your scoreboard to only draw that once? -- Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy Android App Developer Training:http://commonsware.com/training.html -- jason.software.particle --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
The score changes every frame. I like how it works because it's tons of tiny increments. I actually just did the thing I talked about with the reusable char[]. The only caveat is that I have to allocate a new one when the length of the string changes, but that only happens when the score has changed by a factor of 10 and I don't see scores going over 6 digits long. I suppose it's possible someone could play the game forever and score much higher but it's highly unlikely. This is about as efficient as I will ever care to make such a thing. If you want to _never_ allocate, you could make a char[][] where the first dimension is the length of the second dimension arrays. That would be char[1], char[2], char[3], char[4] and so on. That would make it so that if your string size were 5 chars, you would say char[] correctArray = myArrays[5]. I didn't both with that because a few allocations are ok, just not one every tick of the loop. This is ugly but if you need something like this, it does work: I have a class called Util and I put this in it: private final static int[] intSizeTable = { 9, 99, 999, , 9, 99, 999, , 9, Integer.MAX_VALUE }; private final static char[] DigitTens = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', }; private final static char[] DigitOnes = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', }; private final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; // Requires positive x private static int stringSize(int x) { for (int i = 0;; i++) { if (x = intSizeTable[i]) { return i + 1; } } } public static void getChars(int i, int index, char[] buf) { if (i == Integer.MIN_VALUE) { System.arraycopy(-2147483648.toCharArray(), 0, buf, 0, buf.length); } int q, r; int charPos = index; char sign = 0; if (i 0) { sign = '-'; i = -i; } // Generate two digits per iteration while (i = 65536) { q = i / 100; // really: r = i - (q * 100); r = i - ((q 6) + (q 5) + (q 2)); i = q; buf[--charPos] = DigitOnes[r]; buf[--charPos] = DigitTens[r]; } // Fall thru to fast mode for smaller numbers // assert(i = 65536, i); for (;;) { q = (i * 52429) (16 + 3); r = i - ((q 3) + (q 1)); // r = i-(q*10) ... buf[--charPos] = digits[r]; i = q; if (i == 0) break; } if (sign != 0) { buf[--charPos] = sign; } } Then in my game code it looks like this (for my FPS counter): int fps = this.fps; int fpsStringLength = Util.getSize(fps); if (fpsChars.length != fpsStringLength) { // re-allocate fpsChars = new char[fpsStringLength]; } char[] fpsChars = this.fpsChars;
[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?
If you don't need thread synchronization, use StringBuilder instead of StringBuffer. R/ On Mon, May 25, 2009 at 3:47 PM, Robert Green rbgrn@gmail.com wrote: The score changes every frame. I like how it works because it's tons of tiny increments. I actually just did the thing I talked about with the reusable char[]. The only caveat is that I have to allocate a new one when the length of the string changes, but that only happens when the score has changed by a factor of 10 and I don't see scores going over 6 digits long. I suppose it's possible someone could play the game forever and score much higher but it's highly unlikely. This is about as efficient as I will ever care to make such a thing. If you want to _never_ allocate, you could make a char[][] where the first dimension is the length of the second dimension arrays. That would be char[1], char[2], char[3], char[4] and so on. That would make it so that if your string size were 5 chars, you would say char[] correctArray = myArrays[5]. I didn't both with that because a few allocations are ok, just not one every tick of the loop. This is ugly but if you need something like this, it does work: I have a class called Util and I put this in it: private final static int[] intSizeTable = { 9, 99, 999, , 9, 99, 999, , 9, Integer.MAX_VALUE }; private final static char[] DigitTens = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', }; private final static char[] DigitOnes = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', }; private final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; // Requires positive x private static int stringSize(int x) { for (int i = 0;; i++) { if (x = intSizeTable[i]) { return i + 1; } } } public static void getChars(int i, int index, char[] buf) { if (i == Integer.MIN_VALUE) { System.arraycopy(-2147483648.toCharArray(), 0, buf, 0, buf.length); } int q, r; int charPos = index; char sign = 0; if (i 0) { sign = '-'; i = -i; } // Generate two digits per iteration while (i = 65536) { q = i / 100; // really: r = i - (q * 100); r = i - ((q 6) + (q 5) + (q 2)); i = q; buf[--charPos] = DigitOnes[r]; buf[--charPos] = DigitTens[r]; } // Fall thru to fast mode for smaller numbers // assert(i = 65536, i); for (;;) { q = (i * 52429) (16 + 3); r = i - ((q 3) + (q 1)); // r = i-(q*10) ... buf[--charPos] = digits[r]; i = q; if (i == 0) break; } if (sign != 0) { buf[--charPos] = sign; } } Then in my game code it looks like this (for my FPS counter): int fps = this.fps; int fpsStringLength = Util.getSize(fps); if (fpsChars.length != fpsStringLength) { //