Потоки Java: утечка памяти - PullRequest
       2

Потоки Java: утечка памяти

4 голосов
/ 23 января 2012

Я реализовал простой чат сервер-клиент на Java.Вот источник для сервера:

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();
    }
}

Работает нормально, но есть проблема.Для каждого установленного соединения память постоянно растет.Я предполагаю, что проблема в том, что память, выделенная для потоков, впоследствии не освобождается, но я не совсем уверен.Как я могу это исправить?

РЕДАКТИРОВАТЬ: клиентская программа:

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);
        }
    }
}

Ответы [ 3 ]

4 голосов
/ 23 января 2012

Иван,

несколько вещей для работы с Threading.

Никогда не делайте этого:

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

Всегда вставляйте что-то в предложение catch и будьтеlog.error.У вас нет шансов узнать, что это происходит.

Затем все потоки / закрытия и т. Д. Должны перейти в блок finally.В противном случае вы не сможете закрыть все необходимое.

Возможно, вы захотите повторно использовать соединения.Попробуйте это: http://commons.apache.org/pool/

Можете ли вы сказать нам, достигните ли вы sysout для регулярного закрытия соединений?В основном старайтесь создавать записи журнала каждый раз, когда вы открываете соединение, и каждый раз, когда вы закрываете его.Вероятно, вы видите, что вам не хватает.

4 голосов
/ 23 января 2012

Попробуйте сделать

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

и

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

к нестатическому.

Кроме того, я не знаю, как вы проверяете память, но помните, что Java собирает мусор, и вы увидите увеличение использования памяти на начальном этапе до тех пор, пока сборщик мусора (GC) не соберет ее и будет увеличиваться до следующего запуска GC. Так что он постоянно увеличивается без каких-либо провалов в течение долгого времени, только тогда происходит утечка памяти, иначе вам не помешает.


Я запустил приведенный выше код в том виде, в каком он есть, и работал в течение 1-2 часов, при этом на машине Mac используется около 54 МБ памяти с использованием JDK 6. Я не использую JConsole, который поставляется с jdk, чтобы увидеть использование mem. Я не нашел никаких проблем.

Ниже приведен график, как я уже упоминал в моих ответах, у вас есть пик и падение ... в конце, когда я остановил клиента, он плоский. enter image description here

2 голосов
/ 23 января 2012

Попробуйте поместить ваш socket.close () в блок finally , чтобы убедиться, что он работает.

Но я думаю, что в вашем коде могут быть большие проблемы, поскольку вы не используетепул соединений, вы без необходимости открываете новые соединения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...