Sunday, July 13, 2008

Resource Manager Snippet

Basics of Resource Management

Java unlike C/C++ does not allow you to deallocate your own allocated memory. Nor does it allow you to know the size of physical memory used by an object. In games we need to allocate more and more resources as the game gets progressively longer. We wouldn't want to load all 50 1024x768 level backgrounds if we are making a puzzle game with unique backgrounds. Or say 500 64x64 animated sprites for a platformer. The VM will simply exceed its heap size limit and you'll see this nasty little message "java.lang.OutOfMemoryError" you can increase the heap size using VM command line arguments.

java -Xms -Xmx

The defaults are:

java -Xms32 -Xmx128

Even so you don't want to be eating up a users resources especially if you are an applet game or a mobile game. So you need some way of deallocating memory and releasing unused resources.


The Simple Method

The simple method is to allocate (load) resources and deallocate (remove all references to) manually. In the State Machine example posted here there was a cleanup method called on States before a transition occurs which is a good place to remove unused resources or you can just remove quickly loading resources since their inexpensive to reload when needed.

Alternative Resource Handling

A better method would be to encapsulate a reference to the resource within another object making sure that that object is the only one with a reference to the actual resource. The downfall here is that the Resource container object acts as a Proxy pattern to the resource itself. The upside is that you can set the resource up for garbage collection by simple setting the actual resources field to null. Here is a quick example class.

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class ImageResource {

 //The one and only reference to the Image
 private BufferedImage realObject = null;

 private File resourcePath = null;

 public ImageResource(String path)
   throws IOException {
  resourcePath = new File(path); 
  reload();
 }

 public boolean isLoaded() {
  return realObject == null;
 }

 public void reload() throws IOException {
  realObject = ImageIO.read(resourcePath);
 }

 public void release() {
  realObject = null;
 }

 public void render(Graphics2D g) {
  g.drawImage(realObject, 0, 0, null);
 }

 public int getWidth() {
  return realObject.getWidth();
 }

 public int getHeight() {
  return realObject.getHeight();
 }
}
Another option to providing Proxy methods is to use a Visitor pattern for performing operations on specific Resource classes. But that is a more detailed idea for another day perhaps.


Singleton Resource Manager

If you want something to work with here is an example Resource Manager that handles loading Images, AudioClips and manually allocating and dereferencing resources. It's based on using a HashMap as the resource container and setting itself up as a singleton instance.

No comments:

Post a Comment