Java的線程對象是存儲在堆上的,所以,能夠創建多少個線程,受到堆空間的大小限制,同時也受到每個線程的大小的限制,假如線程對象內部有一個非常大的數組字段,那就非常影響能夠創建的線程的大小
我們的例子:
class Task implements Runnable {
//5M堆內存 128k的情況下,最多創建31個線程就掛了
byte[] bytes = new byte[1024 * 128];
@Override
public void run() {
while (true) {
try {
bytes[0] = 1;
Thread.sleep(10_100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
線程對象內部持有一個數組字段,這個數組的大小是128k,我們的測試代碼:
public static void threadTest3() {
int count = 1;
try {
while (true) {
Thread thread = new Thread(new Task());
thread.start();
System.out.println("==============================================" + count++);
}
} catch (Throwable e) {
System.out.println(count);
e.printStackTrace();
}
}
運行測試的時候,我們將堆的內存設置的小一些:
-Xmx5m -Xms5m XX:+PrintGC -XX:-PrintGCDetails
輸出的日志如下:
"C:\Program Files\Java\jdk1.8.0_152\bin\java.exe" -Xmx5m -Xms5m -XX:+PrintGC -XX:-PrintGCDetails com.jiaoyiping.baseproject.concurrent.ThreadTest
[GC (Allocation Failure) 1024K->732K(5632K), 0.0006644 secs]
[GC (Allocation Failure) 1746K->1023K(5632K), 0.0012964 secs]
[GC (Allocation Failure) 1818K->1417K(5632K), 0.0005073 secs]
[GC (Allocation Failure) 2441K->1546K(5632K), 0.0008099 secs]
[GC (Allocation Failure) 2570K->1773K(5632K), 0.0009678 secs]
==============================================1
[GC (Allocation Failure) 2752K->2046K(5632K), 0.0012278 secs]
==============================================2
==============================================3
==============================================4
==============================================5
==============================================6
==============================================7
==============================================8
[GC (Allocation Failure) 2962K->3022K(5632K), 0.0007815 secs]
==============================================9
==============================================10
==============================================11
==============================================12
==============================================13
==============================================14
==============================================15
[GC (Allocation Failure) 3938K->3950K(5632K), 0.0005197 secs]
[Full GC (Ergonomics) 3950K->3132K(5632K), 0.0098480 secs]
==============================================16
==============================================17
==============================================18
==============================================19
==============================================20
==============================================21
==============================================22
[GC (Allocation Failure) 4090K->4220K(5632K), 0.0004522 secs]
[Full GC (Ergonomics) 4220K->3975K(5632K), 0.0085720 secs]
==============================================23
==============================================24
==============================================25
==============================================26
==============================================27
==============================================28
==============================================29
[Full GC (Ergonomics) 4920K->4876K(5632K), 0.0110795 secs]
[Full GC (Allocation Failure) 4876K->4856K(5632K), 0.0086577 secs]
==============================================30
[Full GC (Ergonomics) 5015K->4985K(5632K), 0.0025122 secs]
[Full GC (Allocation Failure) 4985K->4985K(5632K), 0.0022044 secs]
31
java.lang.OutOfMemoryError: Java heap space
at com.jiaoyiping.baseproject.concurrent.Task.<init>(ThreadTest.java:105)
at com.jiaoyiping.baseproject.concurrent.ThreadTest.threadTest3(ThreadTest.java:74)
at com.jiaoyiping.baseproject.concurrent.ThreadTest.main(ThreadTest.java:17)
[Full GC (Ergonomics) 5118K->4995K(5632K), 0.0108311 secs]
[Full GC (Ergonomics) 5107K->5029K(5632K), 0.0034520 secs]
[Full GC (Ergonomics) 5107K->5058K(5632K), 0.0034841 secs]
[Full GC (Ergonomics) 5107K->5064K(5632K), 0.0032645 secs]
[Full GC (Ergonomics) 5107K->5097K(5632K), 0.0034425 secs]
[Full GC (Ergonomics) 5107K->5107K(5632K), 0.0030512 secs]
[Full GC (Ergonomics) 5107K->5107K(5632K), 0.0027000 secs]
[Full GC (Ergonomics) 5109K->5109K(5632K), 0.0026329 secs]
[Full GC (Ergonomics) 5111K->5111K(5632K), 0.0026942 secs]
[Full GC (Ergonomics) 5113K->5113K(5632K), 0.0024612 secs]
[Full GC (Ergonomics) 5116K->5116K(5632K), 0.0028061 secs]
[Full GC (Ergonomics) 5118K->5118K(5632K), 0.0027730 secs]
[Full GC (Ergonomics) 5119K->5119K(5632K), 0.0039374 secs]
[Full GC (Allocation Failure) 5119K->5118K(5632K), 0.0037878 secs]
[Full GC (Ergonomics) 5119K->5119K(5632K), 0.0031486 secs]
[Full GC (Allocation Failure) 5119K->5119K(5632K), 0.0028138 secs]
當創建了30個線程的時候,就出現了堆內存的溢出
如果將bytes的值改變為56K呢,可以創建70個線程
-Xss影響的是棧的深度(比如棧的深度大的話,能夠遞歸調用的次數就越多)
我們構造出來遞歸調用的例子,用來測試-Xss參數對遞歸調用的次數的影響
public static void threadTest4() {
try {
add(0);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
static int add(int count) {
System.out.println("invoke count" + (count + 1));
return add(count + 1);
}
當-Xss設置為128k的時候:
當-Xss設置為256K的時候:
jvm推薦的-Xss設置最少是108k,小於108K的時候,結果是不可預料的
5k-64k 無法創建虛擬機:
4k和以下很大的數值:
64K- 108K
這個值默認是1M我們一般不需要修改,值需要知道-Xss和棧的深度有關即可,通過以上的例子我們得到以下結論:堆內存的大小,和線程對象本身的大小,影響能夠創建的線程的個數,-Xss影響棧的深度
除了Java虛擬機之外,操作系統也會對能創建多少個進程和線程進行限制
通過兩個文件我們可以查看和修改這些限制數:
最大的PID
/proc/sys/kernel/threads-max
最多的線程數:
/proc/sys/kernel/pid_max