Аргументы JVM -Xms и -Xss - PullRequest
0 голосов
/ 19 июня 2019

У меня есть несколько аргументов jvm, но мне сложно их понять.

  1. первый вопрос для аргументов -Xms20m и -Xss2M (первый для размера кучи, а второй для размера стека потока), имеют ли m и M одинаковое значение и означают ли все МБ?
  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 голосов
/ 19 июня 2019

1. Первый вопрос для аргументов -Xms20m и -Xss2M (первый для размера кучи, а второй для размера стека потока), имеют ли m и M одинаковое значение и означают ли они MB?

Да, m и M имеют одинаковое значение и все означают МБ.

2. Второй вопрос, у меня есть следующий фрагмент кода, который, как я ожидаю, оченьбыстро, так как размер стека был установлен на 512M, но код заставляет мою ОС зависать и никогда не выдает ошибку времени выполнения, кто-нибудь знает, почему это так?

Прежде всего, Java не использует только память Heap,В некоторых случаях JVM использует память без кучи (Call Tack, Metaspace и т. Д.). Этот вопрос отвечает на эту ситуацию.Поэтому в стеке потоков используется память без кучи.

Доказательство:

Запустите приложение XX: NativeMemoryTracking = summary и проверьте используемую память с помощью jcmd VM.native_memory команда.Связанный javadoc здесь .

Сначала запустите приложение с параметрами -XX: NativeMemoryTracking = summary -Xms20m -Xss2M и результатом:

Отслеживание собственной памяти:

Всего: зарезервировано = 4581409 КБ, зафиксировано = 171605 КБ

  • Куча Java (зарезервировано = 3121152 КБ, зафиксировано = 20480 КБ) (карта: зарезервировано = 3121152 КБ,совершено = 20480 КБ)

  • Тема (зарезервировано = 21567 КБ, зафиксировано = 21567 КБ) (поток № 16) (стек: зарезервировано = 21504 КБ, зафиксировано = 21504 КБ) (malloc = 45 КБ # 82) (arena = 18KB # 27)

А затем запустите то же приложение с java -XX: NativeMemoryTracking = summary -Xms20m -Xss512M параметрами и результатом:

Отслеживание собственной памяти:

Всего: зарезервировано = 7714849 КБ, зафиксировано = 3305045 КБ

  • Куча Java (зарезервировано = 3121152 КБ, зафиксировано = 20480 КБ)(карта: зарезервировано = 3121152 КБ, зафиксировано = 20480 КБ)

  • Тема (зарезервировано = 3155007 КБ, зафиксировано = 3155007 КБ) (поток # 16) (стек: зарезервировано = 3154944KB, зафиксировано = 3154944KB) (malloc = 45KB # 82) (arena = 18KB # 27)

Как видите, кучапамять не изменилась в обоих случаях, но собственная память потока увеличивается с последним случаем.Потому что мы увеличиваем размер каждого стека.Таким образом, приложение никогда не выдает ошибку времени выполнения, так как в стеке не используется куча памяти.

Примечание. Зарезервированная память представляет собой общий объем памяти, который наше приложение может потенциально использовать.И наоборот, выделенная память равна объему памяти, используемому нашим приложением прямо сейчас.

Примечание 2. Для каждого потока JVM создает один стек времени выполнения, который хранится здесь.Каждый блок этого стека называется активационной записью / кадром стека, в котором хранятся вызовы методов.Все локальные переменные этого метода хранятся в соответствующем кадре.После завершения потока его стек во время выполнения будет уничтожен JVM.Это не общий ресурс.

0 голосов
/ 19 июня 2019

И м, и М означают одно и то же.

StackSize устанавливается для каждого потока. Таким образом, чтобы превысить ограничение в 512 МБ, вам нужно создать действительно большую локальную переменную. Не то, что будет указано в куче.

Xss обычно устанавливается в порядке нескольких килобайт для учета больших стеков, с кучей вещей, таких как счетчики и т. Д. В каждом методе в кадре стека. Если вы хотите нарушить ограничение, вам лучше написать бесконечную рекурсию, в которой каждый метод выделяет несколько локальных переменных.

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.

0 голосов
/ 19 июня 2019

Ответ на ваш первый вопрос: Да . Все подразумевает, что это мегабайт. Что касается вашего второго вопроса, причина довольно очевидна.

Вы создаете новую функцию Thread in stackLeakByThread() каждый раз, когда эта infinity loop повторяется, даже не спя (я не думаю, что Thread.sleep() будет здесь полезно). Я предполагаю, что вы ожидаете ошибку, связанную с памятью. Но в приведенном вами фрагменте кода вы едва создаете новую переменную, которая может использовать много памяти.

Когда вы создаете новый поток и запускаете его, он запускается на процессоре, а не в памяти. Итак, работа, которую вы дали, - это довольно интенсивный бесконечный цикл Таким образом, нет конца потокам, хотя создаются новые Thread s с тем же заданием.

Если мы рассмотрим однопоточный процессор, то только один поток (не как современные многоядерные процессоры) может одновременно обрабатывать эти процессоры. Чтобы реализовать возможность многозадачности, процессоры ждут / спят поток, давая другому возможность обработать / выполнить. Этот сон может варьироваться от наносекунд до миллисекунд. Таким образом, CPU дает возможность каждому потоку обрабатываться, пока не вернется к ранее обработанному потоку. Это время ожидания может отличаться в зависимости от количества потоков, которое ЦП должен обработать. Многоядерные процессоры также одинаковы, но для демонстрации такого поведения потребуется больше времени (но в вашем примере это будет от пары секунд до нескольких минут из-за этого экстремального создания Thread), следовательно, они обычно имеют Hyper-Threading (несколько потоков за один раз они могут выполнить).

Теперь вы должны увидеть в своем примере, что вызывает зависание ОС. Процессор сложил все потоки, и он даже не даст возможности обрабатывать потоки ОС, пока не обработает ваше приложение Thread s. Вот почему ваша ОС в конечном итоге остановилась так же, как и приложение.

Вы могли бы иметь представление из этого документа об этом процессоре - Связи потоков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...