提问者:小点点

Tomcat 7 FreeBSD 7.2(32位)多线程应用程序抛出内存错误:无法创建本机线程


情况:有基于 freebsd 7.2 的服务器,安装了 tomcat 7。Tomcat 7运行巨大的多线程服务器应用程序,该应用程序通过ServerSocket从一些不同的设备读取数据。因此,对于不同的设备,每个端口都有一些侦听器线程。当设备被授权时,侦听器会创建一个从授权设备收集数据的新线程(每个线程 1 个设备),顺便说一下,传入的数据并不那么大。还有客户端的 Web 套接字侦听器,它的工作方式相同 - 每个客户端 1 个线程。这一切都非常好,直到设备数量从 200 增加到 1500(客户端数量也增加了,接近 300)。理想情况下,进程必须与 3000 多个活动线程一起工作,但它会压缩。

以下是应用程序所基于的线程池的代码。

public class MultiThreadPool {

private static final int INITIAL_POOL_SIZE = 1250;
private final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
private final ThreadPoolExecutor exec = new ThreadPoolExecutor(INITIAL_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, queue, new ThreadFactory() {

    @Override
    public Thread newThread(Runnable r) {
        Thread th = new Thread(r);
        //th.setDaemon(true);
        th.setContextClassLoader(null);
        th.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

            @Override
            public void uncaughtException(Thread t, Throwable e) {
                //t.setDaemon(true);
                //throw new UnsupportedOperationException("Not supported yet.");
            }
        });
        return th;
    }
});

private static class SingletonHolder {

    private final static MultiThreadPool instance = new MultiThreadPool();
}

private static MultiThreadPool getInstance() {
    return SingletonHolder.instance;
}

public MultiThreadPool() {
}

public static void initPool() {
    getInstance();
}

public static void executeRunnable(Runnable r) {
    try {
        getInstance().exec.execute(r);
    } catch (OutOfMemoryError e) {
        System.out.println("** Out of memory: " + e.getMessage());
    }
}

public static void stopPool() {
    getInstance().exec.shutdownNow();
    //getInstance().executor.shutdownNow();
}
}

所有线程都在通过ExecuteRunnable(Runnable r)过程运行。例如,将INITIAL_POOL_SIZE(ThreadPoolExecutor的核心大小)增加到1300会导致OutOfMemoryError:无法创建本机线程。同样,如果INITIAL_POOL_SIZE保持在1250,那么队列中的另一个线程在一些核心线程未完成之前根本不工作。这导致客户端在这两种情况下都无法正常工作。

我已经尝试使用-Xss,-server,-Xms,-Xmx,-Xss,perm size等来操作JVM。甚至使用loader.conf和login.conf增加了操作系统硬限制。但所有这些都没有多大帮助或使情况变得更糟。freebsd 中是否有另一个限制,可以通过部署具有其他配置的内核来增加?

无论如何,我需要增加服务器上活动线程的数量来处理全套设备和客户端。顺便说一句,设备至少每5秒发送一次数据。

请告诉我解决此问题的正确方法!

附言:这个应用程序是由另一个人创建的,所以我不能说太多,因为它真的很庞大。但如果您需要,我会尽力为您提供更多信息。


共1个答案

匿名用户

不管内存如何,操作系统似乎受限于它可以创建的线程数量。根据您使用的操作系统,查看限制,并查看是否可以增加数量。

例如,对于mac,您可以通过

sysctl kern.num_threads
kern.num_threads: 10240

对于linux

cat /proc/sys/kernel/threads-max
3500

等等。

您可以通过两种方式解决此问题。

  1. 增加数量
  2. 使用线程池而不是创建数千个线程(通常我更喜欢这个想法)。