简体   繁体   中英

Memory problems with frequent Integer.toString() conversions

I'm currently in the process of porting a game developed in C# (for Windows Phone) to Java (Android).

We're having memory issues in the Java version which, after profiling, seem to be coming from a huge number of String objects in memory, evidently due to the immutable nature of String 's. Now, I've managed to trace this down to the method which renders the player's score to the screen, where a Integer.toString() is used every time the score changes (many times per second). I can't really use a StringBuilder (this is what we have in the C# version) because the text rendering methods of the framework we're using only accept String 's as arguments, therefore a conversion occurs anyways.

Is this a common problem in Java? Can anyone recommend a solution (aside from contacting the framework devs to ask them to modify their methods!)?

Update:

The game is very fast-paced and the score is partly based on the time elapsed since the start of the current "stage". It's updated 15 times per second.

We don't keep a reference to the string, but I'm thinking maybe the framework is leaking or duplicating these strings so I'm trying to look into that (it's not a public framework and to my knowledge it hasn't been used for this kind of fast-paced game yet).

The pooling is a good suggestion and I thought of trying that but the scoring system would have to be modified in order to have a fixed set of values.

I'm not sure if it helps in your particular case, but in general when you have some fixed set of string values that you're operating with, it makes sense to add all of them to string pool. In this case, you can force JVM to not create objects on the heap for each new string but rather utilize string pool.

You'll have to change your code to return strings from pool, like so for example:

return String.valueOf(123).intern();

Some additional explanation from javadoc:

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

We ended up solving the problem by creating our own modifiable string class backed by a fixed length char array, and writing our own text rendering methods with zero allocation once initialized.

After this, everything ran much more smoothly but we still had a few "freezes" caused by GC. After profiling, it turned out this was due to the large amount of iterators created in loops during the main game loop. We then wrote a custom array class which uses a pool of iterators, and now everything runs great!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM