JVM参数-Xms和-Xss

时间:2019-06-19 06:19:36

标签: java jvm

我有几个jvm参数,但是很难理解它们。

  1. 第一个问题是参数-Xms20m和-Xss2M(第一个是堆大小,第二个是线程堆栈大小),m和M含义相同,均表示MB吗?
  2. 第二个问题是,我有以下代码片段,由于堆栈大小设置为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();
    }
}

3 个答案:

答案 0 :(得分:0)

第一个问题的答案是。所有人都暗示着它是兆字节。关于第二个问题,原因很明显。

每次Thread都在没有休眠的情况下进行迭代,就会在stackLeakByThread()函数中创建一个新的infinity loop(我认为Thread.sleep()不会在这里有所帮助)。我猜您正在期待与内存相关的错误。但是在给出的代码片段中,您几乎没有创建一个可能占用大量内存的新变量。

创建新线程并启动时,它在CPU而不是内存上运行。因此,您提供的工作是非常激烈的无限循环。因此,尽管使用相同的作业创建了新的Thread,但是线程没有尽头。

如果考虑单线程CPU,则这些CPU一次只能处理一个线程(与现代多核CPU不同)。为了完成多任务功能,CPU会等待/休眠一个线程,从而使另一个线程有机会处理/执行。睡眠时间可以在几纳秒到几毫秒之间变化。这样,CPU使每个线程都有机会进行处理,直到回到先前处理的线程为止。此休眠时间可能因CPU必须处理的线程数而有所不同。多核CPU也一样,但是显示这种行为需要花费更多时间(但在您的示例中,由于这种极端Thread的创建,可能需要几秒钟到几分钟),因此它们通常具有hyper-threading(一次可以执行的线程很少)功能。

现在,您应该在示例中看到导致操作系统卡死的原因。 CPU堆积了所有线程,在处理应用程序Thread之前,它甚至没有机会处理操作系统的线程。这就是为什么您的OS和应用程序最终都会停滞的原因。

您可能从this document了解有关此CPU-线程关系的信息。

答案 1 :(得分:0)

  

1。第一个问题是参数-Xms20m和-Xss2M(第一个是堆大小,第二个是线程堆栈大小),m和M含义相同,均表示MB吗?

是的,m和M含义相同,均表示MB。

  

2。第二个问题是,我有以下代码片段,由于堆栈大小设置为512M,我希望很快得到运行时错误,但是该代码导致我的操作系统卡住,从不给我运行时错误,有人知道为什么吗?

首先,Java不只使用堆内存。 JVM在某些情况下会使用非堆内存(调用方法,元空间等)。 This question回答这种情况。因此线程堆栈使用非堆内存。

证明:

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

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

  

本机内存跟踪:

     

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

     
      
  • Java Heap(保留= 3121152KB,已提交= 20480KB)                           (mmap:reserved = 3121152KB,committed = 20480KB)

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

  •   

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

  

本机内存跟踪:

     

总数:保留= 7714849KB,已提交= 3305045KB

     
      
  • Java Heap(保留= 3121152KB,已提交= 20480KB)                           (mmap:reserved = 3121152KB,committed = 20480KB)

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

  •   

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

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

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

答案 2 :(得分:0)

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个long变量。如果堆栈足够深,则将超过Xss限制。