概述
与-Xss类似,我们也可以使用-XX:ThreadStackSize参数来设置栈的大小,但是二者是有区别的。
单位不同
-Xss的最小单位是字节(B);而-XX:ThreadStackSize的最小单位是千字节(KB)。
-XX:ThreadStackSize=1024
或
-XX:ThreadStackSize=1k
由于其最小单位是kb,则其大小为1024*1024=1M
相当于
-Xss1m
或
-Xss1024k
-Xss与-XX:ThreadStackSize混用出现的不同
我们编写一个很小的程序来进行验证:
public class Main {
public static void main(String[] args) {
System.out.println("Thread test!");
try{
for(int i=1;i<102400;i++){
new Thread(new Runnable() {
@Override
public void run() {
try{
Thread.sleep(1000000);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
System.out.println("i=" + i);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
该程序是在主线程中使用循环语句创建102400个子线程,每个子线程创建后保持睡眠状态。
1、主线程启动只会以-Xss设置的大小为基础,而无视-XX:ThreadStackSize的设置
java -jar -Xss1 -XX:ThreadStackSize=100 -XX:MaxMetaspaceSize=10m -XX:-UseCompressedClassPointers -Xmx100m simple-em/target/simple-em-1.0.0-SNAPSHOT-full.jar
程序会直接报错而无法启动:
The Java thread stack size specified is too small. Specify at least 180k
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
下面我们将参数改变一下顺序,看看会发生什么:
java -jar -XX:ThreadStackSize=100 -Xss1 -XX:MaxMetaspaceSize=10m -XX:-UseCompressedClassPointers -Xmx100m simple-em/target/simple-em-1.0.0-SNAPSHOT-full.jar
程序依然无法启动,而错误的原因和上面的是一样的。那么也就是说主线程启动的时候只会读取-Xss所设置的栈大小并根据该值启动自身,而无视于-XX:ThreadStackSize设置的值。
2、除主线程外,其他线程的线程栈设置原则——谁最后出现谁说了算
下面我们将-Xss的值设置得大一些,以便使主线程正常运行。
java -jar -Xss1m -XX:ThreadStackSize=100 -XX:MaxMetaspaceSize=10m -XX:-UseCompressedClassPointers -Xmx100m simple-em/target/simple-em-1.0.0-SNAPSHOT-full.jar
此时程序正常运行,但是由于我们的内存设置其实并不能支撑程序启动102400个线程,但是由于主线程只是在运行一个循环,但是它却不会退出。虽然主线程在运行,但是其实程序已经报错,我们可以使用idea杀掉主线程(由于我使用idea下的Terminal运行的上述命令)会发现程序已经报错,如下:
[6.892s][warning][os,thread] Failed to start thread "Unknown thread" - _beginthreadex failed (EACCES) for attributes: stacksize: 100k, flags: CREATE_SUSPENDED STACK_SIZE_PARAM_IS_A_.
[6.893s][warning][os,thread] Failed to start the native thread for java.lang.Thread "Thread-30364"
Exception in thread "main" java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
at java.base/java.lang.Thread.start0(Native Method)
at java.base/java.lang.Thread.start(Thread.java:802)
at com.dokbok.study.simpleem.Main.main(Main.java:19)
我们可以看出,每个线程分配的线程线大小为100k,这是我们通过命令中的-XX:ThreadStackSize=100设置的值,说明-XX:ThreadStackSize=100的设置是生效的。
我们再次将命令的顺序进行变更:
java -jar -XX:ThreadStackSize=100 -Xss1m -XX:MaxMetaspaceSize=10m -XX:-UseCompressedClassPointers -Xmx100m simple-em/target/simple-em-1.0.0-SNAPSHOT-full.jar
使用同样的方式使主线程停下来,我们看到的错误如下:
[6.029s][warning][os,thread] Failed to start thread "Unknown thread" - _beginthreadex failed (EACCES) for attributes: stacksize: 1024k, flags: CREATE_SUSPENDED STACK_SIZE_PARAM_IS_A.
[6.029s][warning][os,thread] Failed to start the native thread for java.lang.Thread "Thread-30206"
Exception in thread "main" java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
at java.base/java.lang.Thread.start0(Native Method)
at java.base/java.lang.Thread.start(Thread.java:802)
at com.dokbok.study.simpleem.Main.main(Main.java:19)
可以看到,每个线程栈分配的大小变成了1024k,这正是通过命令中的-Xss1m设置的。这说明,每个线程分配的线程栈的大小是-Xss与-XX:ThreadStackSize的最后出现的顺序所决定的。