How to Avoid Garbage Collection Delays in Java Games? (Best Practices)

How can I avoid garbage collection delays in Java games? (Best Practices)

I've worked on Java mobile games... The best way to avoid GC'ing objects (which in turn shall trigger the GC at one point or another and shall kill your game's perfs) is simply to avoid creating them in your main game loop in the first place.

There's no "clean" way to deal with this and I'll first give an example...

Typically you have, say, 4 balls on screen at (50,25), (70,32), (16,18), (98,73). Well, here's your abstraction (simplified for the sake of this example):

n = 4;
int[] { 50, 25, 70, 32, 16, 18, 98, 73 }

You "pop" the 2nd ball which disappears, your int[] becomes:

n = 3
int[] { 50, 25, 98, 73, 16, 18, 98, 73 }

(notice how we don't even care about "cleaning" the 4th ball (98,73), we simply keep track of the number of balls we have left).

Manual tracking of objects, sadly. This how it's done on most current well-performing Java games that are out on mobile devices.

Now for strings, here's what I'd do:

  • at game initialization, predraw using drawText(...) only once the numbers 0 to 9 that you save in a BufferedImage[10] array.
  • at game initialization, predraw once "Your score is: "
  • if the "Your score is: " really needs to be redrawn (because, say, it's transparent), then redraw it from your pre-stored BufferedImage
  • loop to compute the digits of the score and add, after the "Your score is: ", every digit manually one by one (by copying each the time the corresponding digit (0 to 9) from your BufferedImage[10] where you pre-stored them.

This gives you best of both world: you get the reuse the drawtext(...) font and you created exactly zero objects during your main loop (because you also dodged the call to drawtext(...) which itself may very well be crappily generating, well, needless crap).

Another "benefit" of this "zero object creation draw score" is that careful image caching and reuse for the fonts is not really "manual object allocation/deallocation", it's really just careful caching.

It's not "clean", it's not "good practice" but that's how it's done in top-notch mobile games (like, say, Uniwar).

And it's fast. Darn fast. Faster than anything involving the creation of object.

P.S: Actually if you carefully look at a few mobile games, you'll notice that often fonts are actually not system/Java fonts but pixel-perfect fonts made specifically for each game (here I just gave you an example of how to cache system/Java font but obviously you could also cache/reuse a pixel-perfect/bitmapped font).

Android Game Garbage Collection Lag alternatives?

Try using a HashMap<String,Bitmap> and initialize it such that there is a key for every image you need, and make the key the image name. Then create a function, where you can ask for the image using the key, and the function will look for it in the map. If the bitmap at the key is null, then load the bitmap and set it to the key. When needed you can iterate over the hashmap using an iterator. Every time you load a bitmap, track the size of all bitmaps in the map by adding the size of the new bitmap to a member field. When the total size of all bitmaps starts to near a threshold you set, figure out a way of choosing bitmaps that are no longer needed at this second, and call bitmap.recycle, set the value at that key to null, subtract the size of the removed bitmap from the total size of all bitmaps, and notify the garbage collector.

This will solve some performance issues with array lists, and help to clean memory as fast as possible. The tricky thing will be deciding what bitmaps to release, and if you want, predicting or knowing before needed: which bitmaps to get into memory.

When drawing sprites, the easiest way is to know the offset, and the current sprite. For example if you have a 500x200 sprite, that has 5 frames on the first row, and 5 frames on the second row (so 5 columns 2 rows), and you know that the progression of the sprites it left to right, so from (0,0) to (5,0) and then down 1 and left to right again (1,0) to (1,5) and then back to start at (0,0), then you can create a simple function that will give you what you need.

In both OpenGL and Canvas, I was able to use the offsets to calculate which portion of the whole bitmap to draw depending on the current frame, so that I never had more than 1 copy of the bitmap in memory at any time, even if there were 100 on screen objects using it.

Finally as I said before in the comments, you will want to minimize as much as possible the size of all the sprite sheets.

Does garbage collection change the object addresses in Java?

I read that garbage collection can lead to memory fragmentation problem at run-time.

This is not an exclusive problem of garbage collected heaps. When you have a manually managed heap and free memory in a different order than the preceding allocations, you may get a fragmented heap as well. And being able to have different lifetimes than the last-in-first-out order of automatic storage aka stack memory, is one of the main motivations to use the heap memory.

To solve this problem, compacting is done by the JVM where it takes all the active objects and assigns them contiguous memory.

Not necessarily all objects. Typical implementation strategies will divide the memory into logical regions and only move objects from a specific region to another, but not all existing objects at a time. These strategies may incorporate the age of the objects, like generational collectors moving objects of the young generation from the Eden space to a Survivor space, or the distribution of the remaining objects, like the “Garbage First” collector which will, like the name suggests, evacuate the fragment with the highest garbage ratio first, which implies the smallest work to get a free contiguous memory block.

This means that the object addresses must change from time to time?

Of course, yes.

Also, if this happens,

  1. Are the references to these objects also re-assigned?

The specification does not mandate how object references are implemented. An indirect pointer may eliminate the need to adapt all references, see also this Q&A. However, for JVMs using direct pointers, this does indeed imply that these pointers need to get adapted.


  1. Won't this cause significant performance issues? How does Java cope with it?

First, we have to consider what we gain from that. To “eliminate fragmentation” is not an end in itself. If we don’t do it, we have to scan the reachable objects for gaps between them and create a data structure maintaining this information, which we would call “free memory” then. We also needed to implement memory allocations as a search for matching chunks in this data structure or to split chunks if no exact match has been found. This is a rather expensive operation compared to an allocation from a contiguous free memory block, where we only have to bump the pointer to the next free byte by the required size.

Given that allocations happen much more often than garbage collection, which only runs when the memory is full (or a threshold has been crossed), this does already justify more expensive copy operations. It also implies that just using a larger heap can solve performance issues, as it reduces the number of required garbage collector runs, whereas the number of survivor objects will not scale with the memory (unreachable objects stay unreachable, regardless of how long you defer the collection). In fact, deferring the collection raises the chances that more objects became unreachable in the meanwhile. Compare also with this answer.

The costs of adapting references are not much higher than the costs of traversing references in the marking phase. In fact, non-concurrent collectors could even combine these two steps, transferring an object on first encounter and adapting subsequently encountered references, instead of marking the object. The actual copying is the more expensive aspect, but as explained above, it is reduced by not copying all objects but using certain strategies based on typical application behavior, like generational approaches or the “garbage first” strategy, to minimize the required work.

How to stop Garbage collection in Android 2.3.3

Garbage Collector is a daemon thread. You can neither stop it nor call it. You can just make a request, eg.- System.gc(), to the garbage collector.

Plus, garbage collector helps improving the performance.

If you do not want to get your objects getting collected by GC then just Hold the reference.

If your object is getting collected prematurely, it is a symptom that you have a bug in the design of your application.

How do i stop the android garbage collector? Is it possible?

I guess you are willing to avoid getting lagged by the gc.
If this is the case, your question is similar to this one.

Basically you can't stop the gc but you can force a call using System.gc().

Best practices for reducing Garbage Collector activity in Javascript

A lot of the things you need to do to minimize GC churn go against what is considered idiomatic JS in most other scenarios, so please keep in mind the context when judging the advice I give.

Allocation happens in modern interpreters in several places:

  1. When you create an object via new or via literal syntax [...], or {}.
  2. When you concatenate strings.
  3. When you enter a scope that contains function declarations.
  4. When you perform an action that triggers an exception.
  5. When you evaluate a function expression: (function (...) { ... }).
  6. When you perform an operation that coerces to Object like Object(myNumber) or Number.prototype.toString.call(42)
  7. When you call a builtin that does any of these under the hood, like Array.prototype.slice.
  8. When you use arguments to reflect over the parameter list.
  9. When you split a string or match with a regular expression.

Avoid doing those, and pool and reuse objects where possible.

Specifically, look out for opportunities to:

  1. Pull inner functions that have no or few dependencies on closed-over state out into a higher, longer-lived scope. (Some code minifiers like Closure compiler can inline inner functions and might improve your GC performance.)
  2. Avoid using strings to represent structured data or for dynamic addressing. Especially avoid repeatedly parsing using split or regular expression matches since each requires multiple object allocations. This frequently happens with keys into lookup tables and dynamic DOM node IDs. For example, lookupTable['foo-' + x] and document.getElementById('foo-' + x) both involve an allocation since there is a string concatenation. Often you can attach keys to long-lived objects instead of re-concatenating. Depending on the browsers you need to support, you might be able to use Map to use objects as keys directly.
  3. Avoid catching exceptions on normal code-paths. Instead of try { op(x) } catch (e) { ... }, do if (!opCouldFailOn(x)) { op(x); } else { ... }.
  4. When you can't avoid creating strings, e.g. to pass a message to a server, use a builtin like JSON.stringify which uses an internal native buffer to accumulate content instead of allocating multiple objects.
  5. Avoid using callbacks for high-frequency events, and where you can, pass as a callback a long-lived function (see 1) that recreates state from the message content.
  6. Avoid using arguments since functions that use that have to create an array-like object when called.

I suggested using JSON.stringify to create outgoing network messages. Parsing input messages using JSON.parse obviously involves allocation, and lots of it for large messages. If you can represent your incoming messages as arrays of primitives, then you can save a lot of allocations. The only other builtin around which you can build a parser that does not allocate is String.prototype.charCodeAt. A parser for a complex format that only uses that is going to be hellish to read though.

Why are some some resources in Java not garbage collected and must be closed or autoclosed?

why this cannot be automated in some way ?

Because, in general, a class can do anything: there is no easy way for the compiler to know that something was "opened", and thus should be "closed", because Java has no strong notion of ownership of values.

Even if you have a field which is of a type that needs closing, you can't easily guarantee that it won't be returned from a getter, say, to something else which is responsible for closing it.

The only really consistent way to indicate that instances of a class need closing is by implementing the AutoCloseable interface (or Closeable, or some other interface which extends it). If you're using these, IDEs may be able to provide warnings about leaked resources; but these are going to be on a best-effort basis.

Strange Behaviour of Garbage Collector on Tomcat

This looks like a memory leak - if the GC can't free the memory any more, it is most probably due to some code retaining references to unused objects. You should try to track the objects remaining in memory (that graphic tool of yours should have some way to peek into the heap memory regions and give you information on created objects) and make sure you erase any reference to unused objects so the GC can free them.



Related Topics



Leave a reply



Submit