【问题标题】:JVM arguments -Xms and -XssJVM 参数 -Xms 和 -Xss
【发布时间】:2019-11-01 19:28:12
【问题描述】:

我有几个 jvm 参数,但理解起来有些困难。

  1. 第一个问题是关于参数 -Xms20m 和 -Xss2M(第一个是堆大小,第二个是线程堆栈大小),m 和 M 是否具有相同的含义并且都是 MB?
  2. 第二个问题是,我有以下代码 sn-p,由于堆栈大小设置为 512M,因此我预计会很快出现运行时错误,但该代码会导致我的操作系统卡住并且永远不会给我运行时错误,有谁知道这是为什么?

谢谢

/**
 *VM Args:-Xss512M
 */
public class JavaVMStackOOM{
    private void noStop(){
        while(true){
        }
    }
    public void stackLeakByThread(){
        while(true){
            Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    noStop();
                }
            });
            thread.start();
        }
    }
    public static void main(String[]args)throws Throwable{
        JavaVMStackOOM oom=new JavaVMStackOOM();
        oom.stackLeakByThread();
    }
}

【问题讨论】:

  • 请每个问题只问 一个 问题,您问的是两个完全不同的问题,这使您的问题过于宽泛。作为一个简短的评论:使用 512 兆字节的堆栈大小是荒谬的。正常值范围从几千字节到一兆字节左右。

标签: java jvm


【解决方案1】:

1.第一个问题是参数-Xms20m和-Xss2M(第一个是堆大小,第二个是线程堆栈大小),m和M是不是同一个意思,都是MB?

是的,m和M意思一样,都是MB的意思。

2.第二个问题是,我有以下代码 sn-p,由于堆栈大小设置为 512M,我希望它很快就会出现运行时错误,但是代码会导致我的操作系统卡住并且永远不会给我运行时错误,有人知道这是为什么吗?

首先,Java 不仅仅使用堆内存。 JVM 在某些情况下使用非堆内存(Call tack、Metaspace 等)。 This question 回答这个问题。所以线程栈使用非堆内存。

证明:

运行应用程序 XX:NativeMemoryTracking=summary 并使用 jcmd VM.native_memory 命令检查已用内存。相关javadochere.

首先,使用 -XX:NativeMemoryTracking=summary -Xms20m -Xss2M 参数和结果运行应用程序:

本机内存跟踪:

总计:保留=4581409KB,提交=171605KB

  • Java 堆(保留=3121152KB,提交=20480KB) (mmap:保留=3121152KB,提交=20480KB)

  • 线程(保留=21567KB,提交=21567KB) (线程#16) (堆栈:保留=21504KB,提交=21504KB) (malloc=45KB #82) (竞技场=18KB #27)

然后,使用 java -XX:NativeMemoryTracking=summary -Xms20m -Xss512M 参数和结果运行相同的应用程序:

本机内存跟踪:

总计:保留=7714849KB,提交=3305045KB

  • Java 堆(保留=3121152KB,提交=20480KB) (mmap:保留=3121152KB,提交=20480KB)

  • 线程(保留=3155007KB,提交=3155007KB) (线程#16) (堆栈:保留=3154944KB,提交=3154944KB) (malloc=45KB #82) (竞技场=18KB #27)

如您所见,堆内存在两种情况下都没有改变,但线程本机内存随着最后一种情况增加。因为我们增加了每个堆栈的大小。所以应用程序永远不会给出运行时错误,因为堆栈不使用堆内存。

注意:保留内存表示我们的应用程序可能使用的内存总量。相反,提交的内存等于我们的应用现在使用的内存量。

注意 2:对于每个线程,JVM 创建一个存储在这里的运行时堆栈。该堆栈的每个块都称为存储方法调用的激活记录/堆栈帧。该方法的所有局部变量都存储在它们相应的框架中。线程终止后,它的运行时堆栈将被 JVM 销毁。它不是共享资源。

【讨论】:

    【解决方案2】:

    m 和 M 意思相同。

    StackSize 是按线程设置的。因此,要超过 512MB 的限制,您需要创建一个非常大的局部变量。 不会在堆上被引用。

    Xss 通常设置为几 KB 的顺序,以解决大堆栈,堆栈帧上的每个方法中都有一堆东西,如计数器等。 如果你想突破这个限制,你最好编写一个无限递归,其中每个方法分配几个局部变量。

    public class JavaVMStackOOM{
        public void stackLeakByThread(long i){
                stackLeakByThread(i+1);
            }
        }
        public static void main(String[]args)throws Throwable{
            JavaVMStackOOM oom=new JavaVMStackOOM();
            oom.stackLeakByThread(0l);
        }
    }
    

    在此,每个方法将在堆栈上存储 1 个长变量。如果您的堆栈足够深,您将超过 Xss 限制。

    【讨论】:

      猜你喜欢
      • 2013-01-23
      • 2013-01-16
      • 1970-01-01
      • 2012-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多