JVM最大Thread数量

原文地址:http://www.yangguo.info/2013/6/17/22.html

最近研发推送方案,需要大量线程来模拟手机客户端。在模拟手机客户端的时候,单个JVM线程数量始终卡在一万多一点,然后就报如下的错误:”java.lang.OutOfMemoryError:unabletocreatenewnativethread“。我在网上找了很多资料,都是分析32位的,都是准备模拟几千个或者几万个水平。因为我是使用64位的linux,并且要模拟50万,发现很多都不是很详细。对于这个OOM,根本无需多言,网上一堆关于JVM线程数的计算公式,此处我不妨再次引用一次:

(MaxProcessMemory-JVMMemory–ReservedOsMemory)/(ThreadStackSize)=Numberofthreads。MaxProcessMemory:进程最大的寻址空间,关于不同系统的进程默认的最大寻址空间,可以参考如下表格:

OperatingSystemMaximumAddressSpacePerProcessRedhatLinux32bit2GBRedhatLinux64bit3GBWindows98/2000/NT/Me/XP2GBSolarisx86(32bit)4GBSolaris32bit4GBSolaris64bitTerabytes

JVMMemory:Heap+PermGen

ReservedOSMemory:Nativeheap,JNI

通过上面的说明大概就能估算出线程数量:

(MaxProcessMemory<固定值>–Xms<初始化值,最小值>–XX:PermSize<初始化值,最小值>–100m<估算值>)/Xss=Numberofthreads<最大值>

公式已经放在上面了,这个时候各个值的设置地方如下:

Java虚拟机本身:

-Xms,-Xmx,-Xss

系统限制:

/proc/sys/kernel/pid_max

开始我也觉得奇怪,为什么需要修改pid呢?pid不是进程id嘛,我只是创建线程,并不创建进程,pid的大小跟我好像没有关系。查阅资料才发现,同一个进程的多个线程的pid其实是不同的。

/proc/sys/vm/max_map_count

max_map_count文件包含限制一个进程可以拥有的VMA(虚拟内存区域)的数量。虚拟内存区域是一个连续的虚拟地址空间区域。在进程的生命周期中,每当程序尝试在内存中映射文件,链接到共享内存段,或者分配堆空间的时候,这些区域将被创建。调优这个值将限制进程可拥有VMA的数量。限制一个进程拥有VMA的总数可能导致应用程序出错,因为当进程达到了VMA上线但又只能释放少量的内存给其他的内核进程使用时,操作系统会抛出内存不足的错误。如果你的操作系统在NORMAL区域仅占用少量的内存,那么调低这个值可以帮助释放内存给内核用。具体的可以查看redhat的这篇文章:http://www.redhat.com/magazine/001nov04/features/vm/,中文的话是这篇:http://www.oschina.net/translate/understanding-virtual-memory?print

还有注意ulimit-a中参数的大小

当然有人说下面这个两个需要修改,但是我测试下来,好像不用修改也行,反正我没有修改。

/proc/sys/kernel/thread-max

/etc/security/limits.d/90-nproc.conf

注意如果使用

#sysctl-wvm.max_map_count=200000

#sysctl-p

来修改,重启后值会改变,如果想永久改变需要如下操作:

vm.max_map_count=200000直接写到/etc/sysctl.conf中,然后执行sysctl-p

对于我的应用,此处还要设置一个socket端口的取值范围

net.ipv4.ip_local_port_range=102465535

当然对于非socket应用是不需要设置该值的

至于上面各个参数的设置,可以去查看linux方面的一些资料。至于值到底多大,得根据你机器的性能来确定。

相关推荐