参数名称 | 含义 | 默认值 | |
-Xms | 初始堆大小 | 物理内存的1/64(<1GB) | 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制. |
-Xmx | 最大堆大小 | 物理内存的1/4(<1GB) | 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制 |
-Xmn | 年轻代大小(1.4or lator) | 注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小. 增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8 | |
-XX:NewSize | 设置年轻代大小(for 1.3/1.4) | ||
-XX:MaxNewSize | 年轻代最大值(for 1.3/1.4) | ||
-XX:PermSize | 设置持久代(perm gen)初始值 | 物理内存的1/64 | |
-XX:MaxPermSize | 设置持久代最大值 | 物理内存的1/4 | |
-Xss | 每个线程的堆栈大小 | JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右 一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。(校长) 和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"” -Xss is translated in a VM flag named ThreadStackSize” 一般设置这个值就可以了。 | |
-XX:ThreadStackSize | Thread Stack Size | (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.] |
- import java.util.concurrent.atomic.AtomicInteger;
- public class TestThread extends Thread {
- private static final AtomicInteger count = new AtomicInteger();
- public static void main(String[] args) {
- while (true)
- (new TestThread()).start();
- }
- @Override
- public void run() {
- System.out.println(count.incrementAndGet());
- while (true)
- try {
- Thread.sleep(Integer.MAX_VALUE);
- } catch (InterruptedException e) {
- break;
- }
- }
- }
内存:2G
JDK:1.7
测试结果:
Ø 不考虑系统限制
-Xms | -Xmx | -Xss | 结果 |
1024m | 1024m | 1024k | 1737 |
1024m | 1024m | 64k | 26077 |
512m | 512m | 64k | 31842 |
256m | 256m | 64k | 31842 |
在创建的线程数量达到31842个时,系统中无法创建任何线程。
由上面的测试结果可以看出增大堆内存(-Xms,-Xmx)会减少可创建的线程数量,增大线程栈内存(-Xss,32位系统中此参数值最小为60K)也会减少可创建的线程数量。
Ø 结合系统限制
线程数量31842的限制是是由系统可以生成的最大线程数量决定的:/proc/sys/kernel/threads-max,可其默认值是32080。修改其值为10000:echo 10000 > /proc/sys/kernel/threads-max,修改后的测试结果如下:
-Xms | -Xmx | -Xss | 结果 |
256m | 256m | 64k | 9761 |
这样的话,是不是意味着可以配置尽量多的线程?再做修改:echo 1000000 >/proc/sys/kernel/threads-max,修改后的测试结果如下:
-Xms | -Xmx | -Xss | 结果 |
256m | 256m | 64k | 32279 |
128m | 128m | 64k | 32279 |
发现线程数量在达到32279以后,不再增长。查了一下,32位Linux系统可创建的最大pid数是32678,这个数值可以通过/proc/sys/kernel/pid_max来做修改(修改方法同threads-max),但是在32系统下这个值只能改小,无法更大。在threads-max一定的情况下,修改pid_max对应的测试结果如下:
pid_max | -Xms | -Xmx | -Xss | 结果 |
1000 | 128m | 128m | 64k | 582 |
10000 | 128m | 128m | 64k | 9507 |
在Windows上的情况应该类似,不过相比Linux,Windows上可创建的线程数量可能更少。基于线程模型的服务器总要受限于这个线程数量的限制。
总结:
JVM中可以生成的最大数量由JVM的堆内存大小、Thread的Stack内存大小、系统最大可创建的线程数量(Java线程的实现是基于底层系统的线程机制来实现的,Windows下_beginthreadex,Linux下pthread_create)三个方面影响。具体数量可以根据Java进程可以访问的最大内存(32位系统上一般2G)、堆内存、Thread的Stack内存来估算。
OK,这个问题总算完满解决,最后总结下影响Java线程数量的因素:
Java虚拟机本身:-Xms,-Xmx,-Xss;
系统限制:
/proc/sys/kernel/pid_max,
/proc/sys/kernel/thread-max,
max_user_process(ulimit -u),
/proc/sys/vm/max_map_count。
影响创建最大线程数的因素:
-Xms intial java heap size
-Xmx maximum java heap size
-Xss the Stack size for each thread
系统的限制 系统可以设置的最大线程数
其计算公式如下所示:
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
MaxProcessMemory 指的是一个进程的最大内存
JVMMemory JVM内存
ReservedOsMemory 保留的操作系统内存
ThreadStackSize 线程栈的大小
但是发现关掉那些消耗内存的应用程序,但是还是没有什么提高,此时只有系统的限制:
/proc/sys/kernel/pid_max,
/proc/sys/kernel/thread-max,
max_user_process(ulimit -u),
/proc/sys/vm/max_map_count。
终端下输入:ulimit -a方法:
- <span style="line-height: 20.02px; font-family: arial;">core file size (blocks, -c) 0</span>
- <p class="p1"><span class="s1">data seg size (kbytes, -d) unlimited</span></p><p class="p1"><span class="s1">file size (blocks, -f) unlimited</span></p><p class="p1"><span class="s1">max locked memory (kbytes, -l) unlimited</span></p><p class="p1"><span class="s1">max memory size (kbytes, -m) unlimited</span></p><p class="p1"><span class="s1">open files (-n) 524288</span></p><p class="p1"><span class="s1">pipe size (512 bytes, -p) 1</span></p><p class="p1"><span class="s1">stack size (kbytes, -s) 8192</span></p><p class="p1"><span class="s1">cpu time (seconds, -t) unlimited</span></p><p class="p1"><span class="s1">max user processes (-u) 2048</span></p><p class="p1"><span class="s1">virtual memory (kbytes, -v) unlimited</span></p>
这是我修改之后的数据,可以发现open files与max user processes数目都增大了(与以前的数据相比),这里因为修改成功了,以前的数据都没有了。这里主要讲解一下在mac OSX captain下面的修改方式。
进入/Library/LaunchDaemons目录,创建以下两个文件:
limit.maxfiles.plist
limit.maxproc.plist
分别在每个文件下面添加以下文件:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
- "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
- <plist version="1.0">
- <dict>
- <key>Label</key>
- <string>limit.maxfiles</string>
- <key>ProgramArguments</key>
- <array>
- <string>launchctl</string>
- <string>limit</string>
- <string>maxfiles</string>
- <string>524288</string>
- <string>524288</string>
- </array>
- <key>RunAtLoad</key>
- <true/>
- <key>ServiceIPC</key>
- <false/>
- </dict>
- </plist>
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE plist PUBLIC "-//Apple/DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
- <plist version="1.0">
- <dict>
- <key>Label</key>
- <string>limit.maxproc</string>
- <key>ProgramArguments</key>
- <array>
- <string>launchctl</string>
- <string>limit</string>
- <string>maxproc</string>
- <string>2048</string>
- <string>2048</string>
- </array>
- <key>RunAtLoad</key>
- <true />
- <key>ServiceIPC</key>
- <false />
- </dict>
- </plist>
重启之后,执行ulimit -a 会发现和我上面的结果一样了。
至于原理:launch是启动的意思,这就是系统启动时候所执行的文件,(一切皆文件的原理,我喜欢这句话)。