简体   繁体   中英

easiest and best way to make a server queue java

i have a server at the moment which makes a new thread for every user connected but after about 6 people are on the server for more than 15 mins it tends to flop and give me java heap out of memory error i have 1 thread that checks with a mysql database every 30 seconds to see if any of the users currently logged on have any new messages. what would be the easiest way to implement a server queue?

this is the my main method for my server:

public class Server {

    public static int MaxUsers = 1000;
    //public static PrintStream[] sessions = new PrintStream[MaxUsers];
    public static ObjectOutputStream[] sessions = new ObjectOutputStream[MaxUsers];
    public static ObjectInputStream[] ois = new ObjectInputStream[MaxUsers];
    private static int port = 6283;
   public static Connection conn;
       static Toolkit toolkit;
    static Timer timer;

    public static void main(String[] args) {
        try {
            conn = (Connection) Mysql.getConnection();
        } catch (Exception ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("****************************************************");
        System.out.println("*                                                  *");
        System.out.println("*                    Cloud Server                  *");
        System.out.println("*                       ©2010                      *");
        System.out.println("*                                                  *");
        System.out.println("*                   Luke Houlahan                  *");
        System.out.println("*                                                  *");
        System.out.println("* Server Online                                    *");
        System.out.println("* Listening On Port " + port + "                           *");
        System.out.println("*                                                  *");
        System.out.println("****************************************************");
        System.out.println("");
        mailChecker();
        try {
            int i;
            ServerSocket s = new ServerSocket(port);
            for (i = 0; i < MaxUsers; ++i) {
                sessions[i] = null;
            }
            while (true) {
                try {
                    Socket incoming = s.accept();                    
                    boolean found = false;
                    int numusers = 0;
                    int usernum = -1;
                    synchronized (sessions) {
                        for (i = 0; i < MaxUsers; ++i) {
                            if (sessions[i] == null) {
                                if (!found) {
                                    sessions[i] = new ObjectOutputStream(incoming.getOutputStream());
                                    ois[i]= new ObjectInputStream(incoming.getInputStream());
                                    new SocketHandler(incoming, i).start();
                                    found = true;
                                    usernum = i;
                                }
                            } else {
                                numusers++;
                            }
                        }
                        if (!found) {
                            ObjectOutputStream temp = new ObjectOutputStream(incoming.getOutputStream());
                            Person tempperson = new Person();
                            tempperson.setFlagField(100);
                            temp.writeObject(tempperson);
                            temp.flush();
                            temp = null;
                            tempperson = null;
                            incoming.close();
                        } else {
                        }
                    }
                } catch (IOException ex) {
                    System.out.println(1);
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } catch (IOException ex) {
            System.out.println(2);
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
        public static void mailChecker() {
        toolkit = Toolkit.getDefaultToolkit();
        timer = new Timer();
        timer.schedule(new mailCheck(), 0, 10 * 1000);
    }
}

It seems like you have a memory leak. 6 threads is not much. I suspect it is because ObjectInputStream and ObjectOutputStream cache all the objects transmitted. This makes them quite unsuitable for long transfers. You think you are sending an object that is then gc'ed, but it's really being held in memory by the object streams.

To flush the streams cache, use

  objectOutputStream.reset()

after writing your objects with writeObject()

EDIT: To get thread pooling, the SocketHandler can be passed to an Executor instead of starting it's own thread. You create an executor like:

Executor executor = Executors.newFiexThreadPool(MaxUsers);

The executor is created as a field, or at the same level as the server socket. Then after accepting a connection you add the SocketHandler to the executor:

executor.execute(new SocketHandler(...));

However, if your clients are long lived, then this will make little improvement, since the thread startup time is small compared to the amount of work done on each thread. Pools are most effective for executing many small tasks, rather than a few large ones.

As to making the server more robust - some quick hints

  • ensure it is started with sufficient memory, or at least that the maximum memory is set to anticipate the need of 1000 users.
  • use a load test framework, such as Apache JMeter to verify it will scale to the maximum number of users.
  • use a connection pool for your database, and don't hand-code JDBC calls - use an established framework, eg Spring JDBC.
  • Each thread starts with 2MB stack by default. So, if you have 1000 users, then that will use ~2GB of virtual process space just for the stack. ON many 32-bit systems, this is the amount of user space you can have, so there will be no room for data. If you need more users, then either scale out to more processes, with a load balancer passing requests to each process, or look at server solutions that do not require a thread per connection.
  • attention to detail, particularly exception handling.
  • logging, for diagnosing failures.
  • JMX or other managability to monitor server health, with notification to you when values go out of bounds (eg memory/cpu use too high for a long period, or request time slow.)

See Architecture of a Highly Scalable Server

您应该签出Java NIO来构建可伸缩服务器

I would focus attention on why you are running out of heap space, or rather why your program gets an OOM error when 6 connections have been open for some time. Your server should be able to scale to at least many more simultaneous concurrent connections, but it's hard to quantify that number without getting more details about your environment, HW, etc.

You've only posted the main method for your server so it's hard to tell if there are memory leaks, resource leaks, etc. that might be causing you to run out of heap space. Are you running your server with the default heap settings? If so, you might want to try increasing your heap size, as the defaults are quite conservative.

Romain is correct: you should be closing your stream resources in a try { ... } finally { ... } block to make sure you are not leaking resources.

Lastly, you might want to consider passing the backlog parameter to the ServerSocket constructor . This specifies the maximum queue size for incoming connections to that ServerSocket, after which any new connections are refused. But first you still need to figure out why your server cannot handle more than 6 connections.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM