Lucas Cleto
Lucas Cleto

Reputation: 195

Java OutOfMemory when sending images via socket

I created an application that basically uses robot to get and image in the client and sends to the server every few seconds, so I can watch what's going on on another PC. The problem seems to be that it keeps saving the image in an array or something, because after a few seconds, it crashs. I just recieve the image and write it on the screen when I do. Yet, after a while, it gives me an OutOfMemory. Does anyone have a hint about what may be causing it?

Here are the code snippets that were requested:

server:

private class Conexao extends Thread {

    public static final int PORTA = 12000;
    public ObjectOutputStream out;
    public ObjectInputStream in;
    public Image image;
    private boolean fim;

    public Conexao(String ip) throws IOException {
        try {
            Socket socket = new Socket(ip, Conexao.PORTA);
            this.out = new ObjectOutputStream(socket.getOutputStream());
            this.in = new ObjectInputStream(socket.getInputStream());
        } catch (IOException e) {
            throw e;
        }
    }

    public void encerrar() {
        this.fim = true;
    }

    @Override
    public void run() {
        this.fim = false;
        while (!this.fim) {
            Mensagem mensagem = null;

            try {
                mensagem = ((Mensagem) in.readObject());
            } catch (IOException | ClassNotFoundException e) {
            }

            if (mensagem != null) {
                this.image = mensagem.getImage();
                Cliente.this.painel.repaint();
            }
        }
    }
}

client:

private static class Conexao extends Thread {

    private static Image CURSOR;
    static {
        try {
            CURSOR = ImageIO.read(new File("images\\mouse.png"));
        } catch (IOException e) {
            CURSOR = null;
        }
    }

    private ObjectOutputStream out;
    private ObjectInputStream in;

    public Conexao() throws IOException {
        try {
            ServerSocket serverSocket = new ServerSocket(Servidor.PORTA, 1);
            Socket socket = serverSocket.accept();
            this.out = new ObjectOutputStream(socket.getOutputStream());
            this.in = new ObjectInputStream(socket.getInputStream());
        } catch (IOException e) {
            throw e;
        }
    }

    @Override
    public void run() {
        try {
            Robot robot = new Robot();

            for (;;)
                try {
                    Thread.sleep(10);

                    Point p = MouseInfo.getPointerInfo().getLocation();
                    BufferedImage img = robot.createScreenCapture(new Rectangle(0, 0, Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height));
                    if (Conexao.CURSOR != null) {
                        img.getGraphics().drawImage(CURSOR, p.x, p.y, null);
                    } else {
                        Graphics2D g = (Graphics2D) img.getGraphics();
                        g.setColor(Color.WHITE);
                        g.fillOval(p.x - 5, p.y - 5, 10, 10);
                        g.setStroke(new BasicStroke(2));
                        g.setColor(Color.BLACK);
                        g.drawOval(p.x - 5, p.y - 5, 10, 10);
                        g.dispose();
                    }

                    this.out.writeObject(new Mensagem(img, p));
                    this.out.flush();
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                }

        } catch (AWTException e) {
        }
    }
}

Upvotes: 1

Views: 372

Answers (4)

Sean Van Gorder
Sean Van Gorder

Reputation: 3453

Try calling this.out.reset(); after this.out.flush();.

This seems to be an issue with ObjectOutputStream, which (according to the Serialization FAQ and this site) keeps a cache of all objects written to it so that repeated objects can be optimized into cache references. This can also cause problems when a value in the object changes before the object is resent, but the cached object retains the old value. In both cases, calling reset() will fix the issue. Unfortunately, none of this is explained in the class documentation.

Upvotes: 1

Klas Lindbäck
Klas Lindbäck

Reputation: 33273

The OutOfMemory is caused by insufficient heap space.

Some actions you can try:

Make sure you have a good size of heap space available when you run the application. (-Xmx128M on the java command line where 128 is replaced by the number of megabytes you want to asign)

Release all references (by letting the variables go out of scope or by explicitly setting object variables to null) to objects you no longer need after sending a picture.

If that doesn't help try to reuse objects rather than creating new ones.

Upvotes: 1

MadConan
MadConan

Reputation: 3767

Without seeing any code, you are most likely populating a byte[] or ByteArrayOutputStream that is class or instance scoped. You should be writing the content received to a file and then accessing it as necessary. This would mean removing the reference to the content (by having it go out of scope) whenever you switch to the new image.

If you could provide more detail as to how your application works, others should be able to pinpoint the issue.

Upvotes: 0

NPE
NPE

Reputation: 500713

The only concrete hint I can offer without seeing your code is to use a memory profiler, such as VisualVM or YourKit.

Something somewhere is keeping references to objects that it probably shouldn't.

Upvotes: 3

Related Questions