[android-developers] Re: Whole lotta garbage collecting going on.... How do I find out what is being collected?

2009-06-02 Thread David Turner
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?

2009-06-02 Thread Dan Bornstein

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?

2009-06-02 Thread Robert Green

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?

2009-06-02 Thread David Turner
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?

2009-06-01 Thread Dan Bornstein

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?

2009-06-01 Thread Robert Green

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?

2009-05-25 Thread Marco Nelissen
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?

2009-05-25 Thread Robert Green

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?

2009-05-25 Thread Romain Guy

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?

2009-05-25 Thread Mark Murphy

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?

2009-05-25 Thread Robert Green

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?

2009-05-25 Thread Romain Guy

 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?

2009-05-25 Thread Mark Murphy

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?

2009-05-25 Thread Robert Green

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?

2009-05-25 Thread Mark Murphy

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?

2009-05-25 Thread Robert Green

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?

2009-05-25 Thread Jokin

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?

2009-05-25 Thread Tom Gibara
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?

2009-05-25 Thread Robert Green

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?

2009-05-25 Thread Mark Murphy

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?

2009-05-25 Thread Robert Green

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?

2009-05-25 Thread Robert Green

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?

2009-05-25 Thread Raphael

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) {
                                        //