linux服务器上增加线程数量的两种思路

工作中碰到Java程序报错,无法创建本地线程。在这里总结一下。

思路1, 通过ulimit指令限制 shell 多线程程序堆栈的大小,达到增加可用线程数量的目的

个例子取自于一个真实的案例。我们所遇到的问题是系统对我们的多线程程序有如下的限制:

ulimit -v 200000

根据本文前面的介绍,这意味着我们的程序最多只能使用不到 200MB 的虚拟内存。由于我们的程序是一个多线程程序,程序在运行时会根据需要创建新的线程,这势必会增加总的内存需求量。一开始我们对堆栈大小的限制是 1024 (本例子中使用 1232 来说明):

 # ulimit – s 1232

 

当我们的程序启动后,通过 pmap 来查看其内存使用情况,可以看到多个占用 1232KB 的数据段,这些就是程序所创建的线程所使用的堆栈:

 

每当一个新的线程被创建时都需要新分配一段大小为 1232KB 的内存空间,而我们总的虚拟内存限制是 200MB,所以如果我们需要创建更多的线程,那么一个可以改进的方法就是减少每个线程的固定堆栈大小,这可以通过 ulimit – s 来实现:

 # ulimit -s 512 

我们将堆栈大小设置为 512KB,这时再通过 pmap 查看一下我们的设置是否起作用:

从上面的信息可以看出,我们已经成功的将线程的堆栈大小改为 512KB 了,这样在总内存使用限制不变的情况下,我们可以通过本小节介绍的方法来增加可以创建的线程数,从而达到改善程序的多线程性能。

思路2,从JVM着手进行

jvm启动参数之Xss

-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M。在sunos下32位java测试这值为512K。可以根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

"Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread"异常问题本质原因是程序创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。

能创建的线程数的具体计算公式如下:
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
MaxProcessMemory 指的是一个进程的最大内存
JVMMemory JVM内存
ReservedOsMemory 保留的操作系统内存
ThreadStackSize 线程栈的大小

在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,
而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。
由公式得出结论:你给JVM内存越多,那么你能创建的线程越少,越容易发生java.lang.OutOfMemoryError: unable to create new native thread。

--根据测试,这种说法只适用于32位java程序,64位的java不受此限制

 

测试程序

import java.util.concurrent.CountDownLatch;

public class TestNativeOutOfMemoryError {
    public static void main(String[] args) {
        for (int i = 0;; i++) {
            System.out.println("i = " + i);
            new Thread(new HoldThread()).start();
        }
    }
}
class HoldThread extends Thread {
    CountDownLatch cdl = new CountDownLatch(1);
    public HoldThread() {
        this.setDaemon(true);
    }
    public void run() {
        try {cdl.await();} 
        catch (InterruptedException e) {}
    }
}

如果程序确实需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory,JVMMemory,ThreadStackSize这三个因素,来增加能创建的线程数:

a, MaxProcessMemory 使用64位JVM

    经测试在,64位jvm下生成的线程数不受上述公式的制约,值为63260,这个数值应该足够用了,

    测试数据如下, (指令|能启动的线程数量)    

java -Xms512M -Xmx2G -cp . TestNativeOutOfMemoryError   | 63389
java -Xms512M -Xmx8G -cp . TestNativeOutOfMemoryError   | 63260
java -Xms512M -Xmx16G -cp . TestNativeOutOfMemoryError  | 63385
java -Xms512M -Xmx32G -cp . TestNativeOutOfMemoryError  | 63380
java -Xms512M -Xmx64G -cp . TestNativeOutOfMemoryError  |63387

b, JVMMemory   减少JVMMemory的分配(即减少xms/xmx的大小)

c, ThreadStackSize  减小单个线程的栈大小 (-Xss)

 

你可能感兴趣的:(linux服务器上增加线程数量的两种思路)