Java线程:内存泄漏

时间:2012-01-23 17:14:31

标签: java multithreading sockets

我在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 个答案:

答案 0 :(得分:4)

伊万,

与线程有关的一些事情。

永远不要这样做:

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

总是在catch子句中添加一些内容,并将其作为log.error。你没有机会知道它发生了。

然后,所有流/关闭等必须进入finally块。否则你无法确保关闭所有必要的东西。

你可能想要重用连接。试试这个: http://commons.apache.org/pool/

您是否可以告诉我们您是否经常通过sysout关闭连接? 每次打开连接时以及每次关闭连接时,基本上都会尝试创建日志语句。可能你会看到你遗失的东西。

答案 1 :(得分:4)

尝试制作

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机器上使用JDK 6的内存使用量大约为54MB。我没有使用jdk附带的JConsole来查看mem用法。我发现没有问题。

下面是我在我的ans中提到的图表,你有峰值和下降..最后当我停止客户端它是平的。 enter image description here

答案 2 :(得分:2)

尝试将socket.close()放在 finally 块中,以确保它运行。

但我认为你的代码可能有更大的问题,因为你没有使用连接池,你不必要地打开新的连接。