JDK-6529318 : Running in Debug when creating BufferedImages is very slow
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-02-28
  • Updated: 2011-02-16
  • Resolved: 2007-03-30
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Window XP Service Pack 2

A DESCRIPTION OF THE PROBLEM :
When running a program that creates and rendering BufferedImages while in Debug mode (using JBuilder 2006), performance drops 5x over running the same code in non-debug mode under JDK 6.0.

Running the same code under JDK 5.0 (1.5.0_09-b01), shows negligible decrease in performance between Debug and Non-Debug mode.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the attached test program,  All the program does is generate a series of Image objects.  For each,  it converts to JPEG, converts back to Image and then renders the converted image.  In the process numerous BufferedImages are created (over 600).  The output is s simple animation of the word TEXT across a small JFrame.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Execution time should be about the same for Debug vs. non-Debug
ACTUAL -
JDK          Non-Debug            Debug
----------    --------------------       --------------------
1.5            7 sec (45 fps)         7 sec (45 fps)

1.6            4 sec (80 fps)         18 sec (17 fps)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
iimport java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.imageio.stream.*;
import javax.swing.*;
import java.util.*;

public class TestVideoFrameStreamer
{
    private static final int WIDTH = 320;
    private static final int HEIGHT = 240;
    private int m_currentFrame = 0;
    private Component m_imageCreator;

    public TestVideoFrameStreamer()
    {
        // Create, show, and hide a JFrame so we can use its
        // Graphics object later to create images.
        m_imageCreator = new JFrame();
        m_imageCreator.setBounds(-100, -100, 0, 0);
        m_imageCreator.setVisible(true);
        m_imageCreator.setVisible(false);
    }

    /**
     * Generates and returns an Image on-the-fly.  The image will be the next one in our animation sequence.
     */
    private Image getImage()
    {
        Image image = m_imageCreator.createImage(WIDTH, HEIGHT);

        Graphics g = image.getGraphics();
        g.setColor(Color.black);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        g.setColor(Color.yellow);
        g.setFont(new Font("SansSerif", Font.BOLD, 40));
        g.drawString("TEST", m_currentFrame, 100);
        m_currentFrame++;
        return image;
    }

    public byte[] getNext() throws Exception
    {
        if (m_currentFrame >= WIDTH)
        {
            throw new Exception("End of test video stream.");
        }
        byte[] jpegImage = imageToJpeg(getImage());
        return jpegImage;
    }

    public void stop()
    {
        m_currentFrame = WIDTH;
    }

    static class ImageCanvas extends JComponent
    {
        private Image m_image;

        public void setImage(Image image)
        {
            m_image = image;
            repaint();
        }

        public void paint(Graphics g)
        {
            g.drawImage(m_image, 0, 0, null, this);
        }
    }

    /**
     * Performs a test using the given VideoFrameStreamer.
     */
    private static void doStreamerTest(final TestVideoFrameStreamer streamer)
    {
        final JFrame frame = new JFrame();


//        final JLabel label = new JLabel();
        final ImageCanvas label = new ImageCanvas();
        label.setPreferredSize(new Dimension(TestVideoFrameStreamer.WIDTH, TestVideoFrameStreamer.HEIGHT));

        frame.getContentPane().add(label);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);

        (new Thread()
        {
            public void run()
            {
                long start = System.currentTimeMillis();
                long framesProcessed = 0;
                while (true)
                {
                    try
                    {
                        byte[] videoFrame = streamer.getNext();
                        Image image = jpegToImage(videoFrame);
                        // Add some metadata to the image.
                        Graphics g = image.getGraphics();
                        g.setColor(Color.green);
                        String caption = "Frame: " + framesProcessed
                            + "    Time: " + (new Date(System.currentTimeMillis())).toString();
                        g.drawString(caption, 10, HEIGHT - 10);
                        label.setImage(image);
                        framesProcessed++;
                    }
                    catch (Exception ex)
                    {
                        ex.printStackTrace();
                        break;
                    }
                }
                long finish = System.currentTimeMillis();
                long duration = (finish - start) / 1000;
                // HACK
                if (duration == 0) {duration = 1;}
                JOptionPane.showMessageDialog(frame, "Done.\nProcessed " + framesProcessed
                    + " frames in " + duration + " seconds (" + (framesProcessed/duration) + " fps).");
                SwingUtilities.invokeLater(new Runnable()
                {
                    public void run()
                    {
                        System.exit(0);
                    }
                });
            }
        }).start();
    }

    /**
     * Converts a java.awt.Image object to a byte[] in JPEG format.
     */
    public static byte[] imageToJpeg(Image image) throws IOException
    {
        // Use a ByteArrayOutputStream and an ImageWriter to do the conversion.
        Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("jpg");
        if (iter.hasNext())
        {
            ImageWriter writer = iter.next();
            ByteArrayOutputStream rawOutputStream = new ByteArrayOutputStream();
            ImageOutputStream ios = ImageIO.createImageOutputStream(rawOutputStream);
            writer.setOutput(ios);
            writer.write((BufferedImage)image);
            return rawOutputStream.toByteArray();
        }
        return null;
    }

    /**
     * Converts a byte[] in JPEG format to a java.awt.Image object.
     */
    public static Image jpegToImage(byte[] jpeg) throws IOException
    {
        // Use a ByteArrayInputStream and an ImageReader to do the conversion.
        Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix("jpg");
        if (iter.hasNext())
        {
            ImageReader reader = iter.next();
            ByteArrayInputStream rawInputStream = new ByteArrayInputStream(jpeg);
            ImageInputStream iis = ImageIO.createImageInputStream(rawInputStream);
            reader.setInput(iis);
            BufferedImage result = reader.read(0);
            return result;
        }
        return null;
    }

    public static void main(String[] args)
    {
        doStreamerTest(new TestVideoFrameStreamer());
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I can find no work around for this behavior

Comments
EVALUATION Note that JBuilder 2006 uses flags -Djava.compiler=NONE and -Xdebug for debugging session, so this problem seems to be duplicate of 6272174.
30-03-2007