1

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) {
        }
    }
}
Lucas Cleto
  • 195
  • 1
  • 16

4 Answers4

3

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.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
1

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.

Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
  • Calling `System.gc()` is a terrible idea. It certainly will not help here. (See http://stackoverflow.com/questions/2414105/why-is-it-a-bad-practice-to-call-system-gc/2414621#2414621) – Stephen C Oct 25 '13 at 14:26
  • That depends. I think sleskes comment is applicable in this case since all this app does is send an image every few seconds. – Klas Lindbäck Oct 25 '13 at 14:50
  • The JVM will call the GC anyway if it is short of memory. An OOME is only thrown if the GC has tried and failed to reclaim enough memory to continue. Calling the GC explicitly does not help. Not one iota. – Stephen C Oct 25 '13 at 15:24
  • @Stephen Edited out the explicit call. – Klas Lindbäck Oct 25 '13 at 16:01
  • FWIW - sleskes comment is about a specific case where you are trying to reduce disruptive garbage collection pauses ... in a use-case where you have times where you *know* the pause won't be disruptive. It is not relevant here. – Stephen C Oct 26 '13 at 01:02
1

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.

Sean Van Gorder
  • 3,393
  • 26
  • 26
0

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.

MadConan
  • 3,749
  • 1
  • 16
  • 27