Avoidance of Garbage Collection

Is it a good idea to avoid creating a new BufferedImage every time an image is refreshed to avoid java garbage collection, and if so, is it a good idea to have a blank image or blank raster to reset the image to when you want to redraw it? Is there a better way? What I have is this.


import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
/**
 * @author Scott
 *
 */
public class ScreenManager
{
    private BufferedImage bi;
    private Raster blank;
    
    private BufferStrategy bs;
    
    private int width;
    private int height;
    
    public ScreenManager(int width, int height)
    {
        JFrame screenFrame = new JFrame(String.format("%dx%d", width, height));
        screenFrame.setSize(width+6, height+24);
        screenFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        screenFrame.setResizable(false);
        screenFrame.setVisible(true);
        
        this.width = width;
        this.height = height;
        
        screenFrame.createBufferStrategy(2);
        
        bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        blank = bi.getData();
        
        bs = screenFrame.getBufferStrategy();
        
    }
    
    public void drawPixel(int x, int y, Color c)
    {
        bi.setData(blank);
        //bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        bi.setRGB(x,y,c.getRGB());
    }
    
    public void refresh()
    {
        render(bs.getDrawGraphics(), bi);
        bs.show();
    }
    
    public void render(Graphics g, Image i)
    {
        
        g.drawImage(i, 3, 21, null);
    }
}

and


import java.awt.*;

/**
 * @author Scott
 *
 */
public class Main
{
    private int pixelX;
    private int pixelY;
    
    public static void main(String[] args)
    {
        ScreenManager sm = new ScreenManager(320, 240);
        
        for(int i = 0;i < 320; i++)
        {
            if(i == 319) i = 0;
            for(int j = 0;j < 240;j++)
            {
                if(j == 240) j = 0;
                sm.drawPixel(i, j, Color.WHITE);
                sm.refresh();
            }
        }
        
        sm.refresh();
    }
}

Another thing I was wondering was weather the use of something like a blocking queue to manage FPS is a good idea.


int fps = 30;

LinkedBlockingQueue<Thread> bq = new LinkedBlockingQueue<Thread>(1);

while(!exit)
{
    bq.put(new Thread(updater));
    bq.peek().start();
    Thread.sleep(1000/fps);
}

Then have the updater somehow remove it’self from the LinkedBlockingQueue. It prevents more than one updater from running at the same time, but also makes the wait continue while the thread is running.

Always attempt to keep hold of images. They’re expensive to construct and fill up the heap fast.

Cas :slight_smile:

clearing & redrawing -> faster than constructing a new image?

yes, much faster.

tries


bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Raster blank = bi.getData(); 
...clip...
bi.setData(blank); 

Hmm. . Ive never thought resetting a bufferedimage state could be done this way.

But then “bi.setData(raster)” method always creates a copy of the given raster, it it remains unchanged for the entire app lifetime. Maybe I should make a small benchmark and see how it goes.

Copying a raster into a buffered image has never worked for me, so I just copy the pixels.

Don’t go mucking around with Rasters or poking pixels. Use a Graphics2D and draw into the image. That way it’ll all be nice and hardware accelerated.

…or use LWJGL and learn OpenGL instead :slight_smile:

Cas :slight_smile:

Yeah, I went to useing a Graphics gotten from the BufferStrategy to render the image, I was a little dissapointed that they did not have the option to draw a single pixel, I decided to just use a fillRect(x, y, 1, 1); Worked at a good speed even at high resolutions like 1600 x 1200. Although now that I am useing sprites, I am having trouble becasue it seems to take a really long time to draw a buffered image to a Graphics. Is there any way to move the image into the memory on the graphics card so that it can access it quickly?

BufferedImage.setRGB(int x, int y, int rgbcolor) method might be the one you are looking for.

But true, then you must use “Graphics2D g” for general purpose drawings and plotting a single pixel use a parent bufferedImage instance.

Anyone know why graphics canvas does not have setRGB method.

Because under the hood such a method would probably have to create a Graphics, plot a single pixel, and dispose the Graphics. You can imagine that’d be tragically slow.

Cas :slight_smile:

But graphics has all the drawXYZ methods, why not just an optimized drawPixel(x, y). It looks silly to draw 1 pixel line.

If it were there people would use it, and as a setPixel(x,y) method is the wrong way to approach this problem its a good thing its not there.

If you want per-pixel access, then you want an unmanaged image (i.e. not in vram), and direct access to the images databuffer. (i.e. getRaster().getDataBuffer())

If on the other hand you want HW accelerated blitting, you should never grab an images databuffer. (as this will prevent it being cached in vram)