Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Threads: Memory Leak

I implemented simple server-client chat in Java. Here the source for the server:

public class Server {
    final private static int PORT = 50000;

    private static class Read extends Thread {
        private static Socket socket;
        private static String address;

        public Read(Socket socket) {
            this.socket = socket;
            address = socket.getInetAddress().toString().substring(1);
        }

        public void run() {
            try {

                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String msg;

                while (true) {
                    msg = in.readLine();
                    if (msg == null) {
                        in.close();
                        return;
                    }

                    System.out.println(address + ": " + msg);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    private static class Write extends Thread {
        private static Socket socket;

        public Write(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            try {

                PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
                String msg;

                while (true) {
                    if (socket.isClosed()) {
                        out.close();
                        return;
                    }
                    if (stdin.ready()) {
                        msg = stdin.readLine();
                        out.println(msg);
                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket;
        boolean listening = true;

        serverSocket = new ServerSocket(PORT);

        while (listening) {
            Socket socket = serverSocket.accept();
            String address = socket.getInetAddress().toString().substring(1);
            System.out.println("Connection Established " + address);

            Thread read = new Read(socket);     
            Thread write = new Write(socket);

            read.start();
            write.start();

            try {
                read.join();
                write.join();
            } catch(InterruptedException e) {

            }   

            socket.close();
            System.out.println("Connection Closed " + address);
        }
        serverSocket.close();
    }
}

It works fine but there is a problem. For every established connection the memory continuously grows. I presume the problem is that the memory allocated for the threads is not released afterwards but I'm not quite sure. How can I fix that?

EDIT: The client program:

class Client {
    final private static int PORT = 50000;

    private static class Read extends Thread {
        private Socket socket;
        private String address;

        public Read(Socket socket) {
            this.socket = socket;
            address = socket.getInetAddress().toString().substring(1);
        }

        public void run() {
            try {

                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String msg;

                while (true) {
                    msg = in.readLine();
                    if (msg == null) {
                        System.out.println("Connection closed " + address);
                        System.exit(0);
                    }
                    System.out.println(address + ": " + msg);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    private static class Write extends Thread {
        private Socket socket;

        public Write(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            try {

                PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                Scanner sc = new Scanner(System.in);
                String msg;

                while (true) {
                    msg = sc.nextLine();
                    out.println(msg);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) throws IOException {
        PrintWriter out;
        BufferedReader in;
        Scanner sc = new Scanner(System.in);
        while (true) {  //for the test only
            Socket socket = null;
        try {   
            socket = new Socket("78.90.68.125", PORT);
        } catch(java.net.ConnectException e) {
            System.out.println("Connection error: host unreachable");
            System.exit(1);
        }
/*
        String address = socket.getInetAddress().toString().substring(1);
        System.out.println("Connection established " + address);
        Thread read = new Read(socket);     
        Thread write = new Write(socket);

        read.start();
        write.start();

        try {
            read.join();
            write.join();
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
        finally {
*/      
        socket.close();
//      }
        //System.out.println("Connection closed " + address);
        }
    }
}
like image 262
sve Avatar asked Dec 27 '22 07:12

sve


1 Answers

Try making

private static class Read extends Thread {
 private static Socket socket;
 private static String address;

and

private static class Write extends Thread {
 private static Socket socket;

to non-static.

Also, I dont know how you checking for memory, but do remember that Java is garbage collected and you will see increase in memory usage initially till the time garbage collector (GC) collects it and will increase again till next GC run. So it consistently increasing without any dip for long time only then there is a memory leak else you are good to go.


I ran the above code as is and ran for around 1-2 hours and it is steady memory usage of around 54MB on Mac machine using JDK 6. I am not using JConsole that comes with jdk to see mem usage. I found NO issues.

Below is the graph as I mentioned in my ans also, you have peak and dip ..in the end when I stopped client it is flat. enter image description here

like image 133
havexz Avatar answered Jan 13 '23 17:01

havexz