【问题标题】:Java process out of memory when creating thread on CentOS 6在 CentOS 6 上创建线程时 Java 进程内存不足
【发布时间】:2014-01-25 15:34:08
【问题描述】:

在我触发这个nohup java -cp server.jar:mysql-connector.jar com.server.test.EchoMulti & 后不到一个小时,我就得到了这个错误。错误:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread    
    at java.lang.Thread.start0(Native Method)                                            
    at java.lang.Thread.start(Unknown Source)                                            
    at com.server.test.EchoMulti.main(EchoMulti.java:14)

我是服务器和 Java 的新手。这是我在服务器和 Java 中做的第一件事,它是一款适用于 Android 游戏的多人游戏。游戏做得很好,所以有很多人尝试玩多人游戏。我已经修复了 mySQL max_connections 但现在我遇到了问题。我还想知道是否有办法在出现导致崩溃的错误时自动重新启动进程。还有一种在重启时自动启动它的方法。

导致它的 EchoMulti 类:

package com.server.test;
import java.net.*;
import java.io.*;

public class EchoMulti {

    public static void main(String[] args) throws IOException {

        int portNumber = 25003;
        boolean listening = true;

        try (ServerSocket serverSock = new ServerSocket(portNumber)) { 
            while (listening) {
                new EchoServer(serverSock.accept()).start();
            }
        } catch (IOException e) {
            System.err.println("Could not listen on port " + portNumber);
            System.exit(-1);
        }
    }

}

EchoServer 类:

package com.server.test;
import java.net.*;
import java.io.*;
import java.sql.*;
import java.lang.Thread;


public class EchoServer extends Thread {
     private Socket sock = null;

     public EchoServer(Socket sock) {
         super("EchoServer");
         this.sock = sock;
     }

public void run(){
    String url = "jdbc:mysql://IP:3306/DB";
    String username = "USER";
    String password = "PASSWORD";
    Connection con = null;
    Statement sta = null;
    ResultSet resultSet = null;

    try {
        //System.out.println("Connecting database...");
        con = DriverManager.getConnection(url, username, password);
        //System.out.println("Database connected!");
    } catch (SQLException e) {
        throw new RuntimeException("Cannot connect the database!", e);
    }

    try (
        PrintWriter out = new PrintWriter(sock.getOutputStream(), true);                   
        BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
    ) {
        String inputLine;
        while ((inputLine = in.readLine()) != null) {
            if(inputLine.equalsIgnoreCase("get")){
                    SEND SOMETHING
            } else {
                String catched[] = inputLine.split("\\;");
                if(catched[0].equalsIgnoreCase("sub")){
                    SEND SOMETHING
                } else if(catched[0].equalsIgnoreCase("res")){
                    SEND SOMETHING
                }
            }
        }
    } catch (IOException e) {
        System.out.println("Exception caught when trying to listen on port 25003 or listening for a connection");
        System.out.println(e.getMessage());
    } finally {
        //System.out.println("Closing the connection.");
        if (con != null) try { con.close(); } catch (SQLException ignore) {}
        try { sock.close(); } catch (IOException ignore) {} finally {}
    }
}
public void close() throws IOException {
    if (sock != null) sock.close();
}
}

【问题讨论】:

  • 尝试增加 Java 应用程序的内存。
  • 我有一个 1GHz 的 VPS、1GB 内存和 50GB 空间。也许我应该创建一个交换文件?
  • 你对 RAM 的看法是对的 :) 但我设法减少了线程数。

标签: java mysql centos threadpool multiplayer


【解决方案1】:

您也可能在某处发生内存泄漏,或者阻止正确垃圾收集已用内存。

我会做以下三件事。

修改 EchoServer 类 您可以添加一个静态成员来了解当崩溃发生时,内存中现有线程的数量是否是您期望的(它们应该与连接的玩家一样多)。

public class EchoServer extends Thread {
     private Socket sock = null;
     private static Integer CONNECTED = 0;
     public EchoServer(Socket sock) {
         try{
         super("EchoServer");
         this.sock = sock;
         CONNECTED++;
         } catch (Exception ex)
         {
            Logger.getLogger(EchoServer.class.getName()).log(Level.SEVERE, "Currently CONNECTED: "+CONNECTED);
         }
     }

     .... your stuff here

     @Override
     public void finalize(){
         super.finalize();  
         CONNECTED--;
     }
}

如果线程数多于连接的玩家,则有问题。

使用分析器 使用分析器来观察内存使用情况并识别瓶颈。还要确保没有“奇怪”的对象幸存几代,或者在没有玩家增加的情况下内存不会随着时间的推移而增加。 NetBeans 有一个很好的分析器,它也可以通过 TCP 连接到实时应用程序。

使用 -Xmx 使用 java -Xmx1g 启动服务器。

【讨论】:

  • 我使用 Java VisualVM 检查了该应用程序。结果如下:link。当线程开始下降时会发生错误。如果没有运行 jstatd,它会达到大约 1000-1200。似乎记忆不时地下降。当我运行 free -m 时,它几乎已满。以下是错误日志link
  • 您的应用程序没有因为内存不足而崩溃……它是 JVM 本身正在崩溃。这可能发生在您的应用程序中的错误或系统资源被严重过度使用的情况下。在您的情况下,我怀疑存在错误,因为您的分析会话中的堆只有 256Mb,而您说您有 1G 的 RAM。看看stackoverflow.com/questions/6344546/…,看看它是否适合你。
  • 无论如何尝试使用 Xmx 以及 Xss 来控制线程堆栈大小。
  • 我之前没有这个,但现在出现错误时我得到了这个:Resource counter_cpu_share_used red alert on environment mydomain.pl current value: 87 soft limit: 85 hard limit: 95
  • 该日志似乎与 Plesk 相关...我真的不知道 :(
猜你喜欢
  • 1970-01-01
  • 2017-11-09
  • 2017-01-05
  • 1970-01-01
  • 1970-01-01
  • 2017-11-24
  • 2018-05-14
  • 2018-06-11
  • 2012-09-29
相关资源
最近更新 更多