Настройка MaxDirectMemory и MaxHeapMemory для приложений Java

Для моего Java-приложения я пытался ограничить кучу памяти и прямое использование памяти с помощью параметров командной строки.

Я столкнулся со следующей статьей VMware, когда пытался понять больше о структуре памяти приложения Java.

Из статьи я предположил, что параметр -Xmx можно использовать для ограничения использования кучи, а параметр MaxDirectMemory можно использовать для ограничения собственной памяти, которая находится за пределами кучи (Память гостевой ОС на диаграмме). Но результаты меняются, когда я запускаю простую программу. Я использовал ByteBuffer.allocateDirect для выделения собственной памяти, а ByteBuffer.allocate для выделения памяти.

Это 64-битный процессор (OSX) и 64-битная JVM.

Первый Эксперимент

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.*;

public class javalimits {

    public static void main (String [] args)
            throws Exception {

            ArrayList al = new ArrayList();
            for(int i = 0; i< 100;i++) {

                    ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024* 1024);
                    al.add(bb);
                    System.out.println(" Buffer loop "+ i);
                    Thread.sleep(500);
            }
            Thread.sleep(10000);
    }
}

Когда я запустил вышеупомянутую программу без каких-либо опций, она вылетала после 3,6 Гб выделения памяти Когда я использовал опцию "-XX:MaxDirectMemorySize=100g" или "-Xms100g -Xmx100g", он падал после 65 циклов или около 65G выделения памяти.

Я не понимаю

  1. Так как мой физический ОЗУ всего 16G, почему он не зависал после 16G выделения памяти? Что особенного в 64G выделенной памяти?
  2. Как меняются собственные пределы выделения памяти при использовании "-Xms100g -Xmx100g"? Я предположил, что собственные ограничения памяти контролируются только с помощью параметра ""-XX:MaxDirectMemorySize=100g", как показано на приведенной выше схеме в предоставленной мной ссылке. Но результаты отличаются. Настройки памяти Heapsize также изменили пределы прямого буфера памяти.
  3. Что особенного в распределении памяти 3,6 ГБ, если не указаны параметры командной строки?

Второй эксперимент

Я изменил ByteBuffer.allocateDirect на ByteBuffer.allocate для размещения в памяти кучи вместо собственной памяти.

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.*;

public class javalimits {

    public static void main (String [] args)
            throws Exception {

            ArrayList al = new ArrayList();
            for(int i = 0; i< 100;i++) {

                    ByteBuffer bb = ByteBuffer.allocate(1024 * 1024* 1024);
                    al.add(bb);
                    System.out.println(" Buffer loop "+ i);
                    Thread.sleep(500);
            }
            Thread.sleep(10000);
    }
}

Когда я запустил вышеупомянутую программу без каких-либо опций, она потерпела крах после 2,7G выделения памяти. Когда я использовал опцию "-XX:MaxDirectMemorySize=100g", это не имело никакого эффекта. Сбой после 2.7G выделения памяти. Я чувствовал, это имеет смысл. Но когда я добавил опцию "-Xms100g -Xmx100g", она зависала после 48 циклов или около 48G выделения памяти.

Я не понимаю почему,

  1. Так как мой физический ОЗУ всего 16G, почему он не зависал после 16G выделения памяти? Что особенного в 48G выделения кучи?
  2. Что особенного в распределении памяти 2.7G, если не указаны параметры командной строки?

Третий эксперимент

Я включил как allocateDirect, так и функции allocate внутри цикла. когда я добавил опцию "-Xms100g -Xmx100g", он падал после 24 циклов или, по сути, 48G распределения памяти, объединяя оба. (24G родной памяти + 24G памяти кучи)

Может ли кто-нибудь помочь мне понять, где я не прав в понимании структуры памяти Java?(См. Схему в ссылке)

1 ответ

Довольно хорошее объяснение об управлении памятью вы можете найти здесь: https://smarttechie.org/2016/08/15/understanding-the-java-memory-model-and-the-garbage-collection/

ответить на ваши вопросы:

Я не понимаю почему,

  1. Так как мой физический ОЗУ всего 16G, почему он не зависал после 16G выделения памяти? Что особенного в 48G выделения кучи?

Физическая память не является пределом для системы, она может использовать технику обмена. Это позволяет системе удалять редко используемые измененные страницы из физической памяти, чтобы позволить системе более эффективно использовать физическую память для более часто используемых страниц.

Что особенного в 48G, так это то, что ваша система способна обрабатывать только такой объем памяти. Вы можете попробовать поиграть с болотом и позволить системе выделить все 100G.

  1. Что особенного в распределении памяти 2.7G, если не указаны параметры командной строки?

Прежде чем запускать Java из командной строки, проверьте это:

Windows

java -XX:+PrintFlagsFinal -version | findstr /i "HeapSize PermSize ThreadStackSize"

Linux

java -XX:+PrintFlagsFinal -version | grep -iE 'HeapSize|PermSize|ThreadStackSize'

Также вы можете контролировать распределение визуальной памяти через jconsol.

Почему были расположены разные размеры памяти, вы должны прочитать это:

ByteBuffer.allocate () против ByteBuffer.allocateDirect()

Другие вопросы по тегам