Java-XX:ThreadStackSize与-Xss的区别

概述

与-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的最后出现的顺序所决定的。

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注