此篇文章是接上一篇博客“Java OutOfMemory Error引发的JVM参数实测--线程堆栈参数篇”的后续测试。
测试目的:
通过Sun Java 1.6.0_20 32bit 版本运行上篇博客中的Java程序,测试在不同的线程堆栈参数设置的情况下分别可以生成多少个线程。
测试一:
使用默认的Java Xms和Xmx设置,测试生成的Java线程数:
./jre1.6.0_20/bin/java -server TestNativeOutOfMemoryError
..........................
I = 9141
i = 9142
i = 9143
i = 9144
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Unknown Source)
at TestNativeOutOfMemoryError.main(TestNativeOutOfMemoryError.java:9)
Java HotSpot(TM) Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGINT to handler- the VM may need to be forcibly terminated
运行java 程序之前,系统可用内存:
[root@tivbsmv999 ~]# free -m
total used free shared buffers cached
Mem: 3949 2324 1625 0 8 1704
-/+ buffers/cache: 610 3339
Swap: 5951 11 5940
运行java 程序之后,系统可用内存:
内存消耗量 = 1625 - 1246 = 379 Mb
测试二:
将Java Xms和Xmx设置为512m,测试生成的Java线程数:
./jre1.6.0_20/bin/java -server -Xms500m -Xmx500m TestNativeOutOfMemoryError
..........................
i = 10652
运行java 程序之前,系统可用内存:
[root@tivbsmv999 ~]# free -m
total used free shared buffers cached
Mem: 3949 2326 1623 0 9 1705
-/+ buffers/cache: 611 3338
Swap: 5951 11 5940
运行java 程序之后,系统可用内存:
内存消耗量 = 1623 - 1173 = 450 Mb
测试三:
将Java Xms和Xmx设置为1024m,测试生成的Java线程数:
./jre1.6.0_20/bin/java -server -Xms1024m -Xmx1024m TestNativeOutOfMemoryError
..........................
i = 9031
运行java 程序之前,系统可用内存:
[root@tivbsmv999 ~]# free -m
total used free shared buffers cached
Mem: 3949 2328 1621 0 10 1705
-/+ buffers/cache: 612 3337
Swap: 5951 11 5940
运行java 程序之后,系统可用内存:
内存消耗量 = 1621 - 1235 = 386 Mb
测试四:
将Java Xms和Xmx设置为2000m,测试生成的Java线程数:
./jre1.6.0_20/bin/java -server -Xms2000m -Xmx2000m TestNativeOutOfMemoryError
..........................
i = 6009
运行java 程序之前,系统可用内存:
[root@tivbsmv999 ~]# free -m
total used free shared buffers cached
Mem: 3949 2313 1635 0 8 1695
-/+ buffers/cache: 609 3339
Swap: 5951 11 5940
运行java 程序之后,系统可用内存:
内存消耗量 = 1635 - 1343 = 292 Mb
测试五:
将Java Xms和Xmx设置为2400m,测试生成的Java线程数:
./jre1.6.0_20/bin/java -server -Xms2400m -Xmx2400m TestNativeOutOfMemoryError
..........................
i = 4770
运行java 程序之前,系统可用内存:
[root@tivbsmv999 ~]# free -m
total used free shared buffers cached
Mem: 3949 2381 1568 0 9 1761
-/+ buffers/cache: 610 3339
Swap: 5951 11 5940
运行java 程序之后,系统可用内存:
内存消耗量 = 1568 - 1365 = 203 Mb
测试六:
将Java Xms和Xmx设置为256m,测试生成的Java线程数:
./jre1.6.0_20/bin/java -server -Xms256m -Xmx256m TestNativeOutOfMemoryError
..........................
i = 11409
运行java 程序之前,系统可用内存:
[root@tivbsmv999 ~]# free -m
total used free shared buffers cached
Mem: 3949 2381 1567 0 10 1761
-/+ buffers/cache: 610 3339
Swap: 5951 11 5940
运行java 程序之后,系统可用内存:
内存消耗量 = 1567 - 1098 = 469 Mb
测试七:
将Java Xms和Xmx设置为128m,测试生成的Java线程数:
./jre1.6.0_20/bin/java -server -Xms128m -Xmx128m TestNativeOutOfMemoryError
..........................
i = 11803
运行java 程序之前,系统可用内存:
[root@tivbsmv999 ~]# free -m
total used free shared buffers cached
Mem: 3949 2382 1566 0 10 1761
-/+ buffers/cache: 610 3338
Swap: 5951 11 5940
运行java 程序之后,系统可用内存:
内存消耗量 = 1566 - 1090 = 476 Mb
测试结果分析:
1. 上述的测试结果纠正了我之前的错误观念,并不是给JVM 堆(Xmx)分配的内存越多,Java进程可以创建的线程就越多,而且恰恰是相反的。上述的测试结果说明给Xmx分配的内存越多,Java可创建的线程数量越少。从网上找了一些文章得知,堆主要是用来存放对象的,栈是用来执行程序的。JVM中的堆内存(Heap)和栈内存(Stack)的作用非别为:
JVM堆中存的是对象。每一个Java应用都唯一对应一个JVM实例,每个JVM实例唯一对应一个堆。Java堆的唯一目的就是存放对象实例,应用程序在运行中所创建的所有对象实例和数组都在这里分配空间,并由所有的线程所共享。Java中堆内存的分配是自动初始化的。Java中所有对象的存储空间都是在堆内存中进行分配的,但是这个对象的引用却是在栈内存中分配的。也就是在建立一个对象时从堆内存和栈内存都分配内存空间。在堆中分配的空间用来实际建立这个对象,而在栈中分配的内存只是指向这个堆对象的引用而已。
JVM栈中存的是基本数据类型和JVM堆中对象的引用。一个对象的大小是不可估计的,或者说是可以动态变化的,但是在JVM栈中,一个对象只对应了一个4btye的引用。基本数据类型占用的空间一般是1~8个字节。JVM栈是程序运行时单位,决定了程序如何运行,或者说数据如何处理。在Java中,没生成一个线程,就会有一个JVM栈与之对应。因为不同的线程的执行逻辑显然是不同的,所以每个线程都需要一个独立的栈空间来存放该线程的执行逻辑。
从上述堆和栈的作用和区别可以看出,Java进程所能创建的线程数量是跟每个线程占用的JVM栈的大小和系统的可用内存密切相关的。其中每个线程占用的JVM栈的大小是通过参数Xss来设定的。在Xss已定的情况下,分配给JVM堆的内存空间越多,系统的可用内存就越少,所以Java进程可创建的线程数量就越少。
2. 在测试一和测试三中,Java可以创建的线程数量差不多,可以推测默认的堆大小也在1G左右,验证了默认堆的最大值(Xmx)为物理内存的1/4的说法。另外看到有文章说默认堆的最小值(Xms)为物理内存的1/64,这里未做验证。
3. 将上述各个测试中Java程序运行前后的内存消耗量除以生成的线程数量,都可以得出每个线程占用的内存数量大约为0.04 Mb。跟上篇博客“Java OutOfMemory Error引发的JVM参数实测--线程堆栈参数篇”中的Xss的默认值320k是基本吻合的。
参考:
JVM内存管理:
http://yuntai.1kapp.com/?p=528
JVM中堆内存和栈内存详解:
http://www.360doc.com/content/12/0306/17/1429048_192252660.shtml