«1. Обзор

В этой статье мы обсудим API-интерфейсы, предоставляемые Java, которые могут помочь нам понять несколько аспектов, связанных с пространством кучи Java.

Это может быть полезно для понимания текущего состояния памяти JVM и передачи его на аутсорсинг службам мониторинга, таким как StatsD и Datadog, которые затем можно настроить для выполнения упреждающих действий и предотвращения сбоев приложений.

2. Доступ к параметрам памяти

Каждое приложение Java имеет единственный экземпляр java.lang.Runtime, который может помочь нам понять текущее состояние памяти приложения. Статический метод Runtime#getRuntime можно вызвать для получения одноэлементного экземпляра среды выполнения.

2.1. Total Memory

Метод Runtime#getTotalMemory возвращает общее пространство кучи, зарезервированное в настоящее время JVM в байтах. Он включает в себя память, зарезервированную для текущих и будущих объектов. Следовательно, не гарантируется, что он будет постоянным во время выполнения программы, поскольку пространство кучи Java может увеличиваться или уменьшаться по мере выделения большего количества объектов.

Кроме того, это значение не обязательно соответствует используемому объему или максимальному объему доступной памяти.

2.2. Свободная память

Метод Runtime#freeMemory возвращает свободное пространство кучи, доступное для размещения новых объектов в байтах. Она может увеличиться в результате операции сборки мусора, когда после этого будет доступно больше свободной памяти.

2.3. Максимальная память

Метод Runtime#maxMemory возвращает максимальную память, которую JVM попытается использовать. Как только использование памяти JVM достигает этого значения, она не будет выделять больше памяти, а вместо этого будет чаще собирать мусор.

Если объектам JVM по-прежнему требуется больше памяти даже после запуска сборщика мусора, JVM может сгенерировать исключение времени выполнения java.lang.OutOfMemoryError.

3. Пример

В приведенном ниже примере мы инициализируем ArrayList и добавляем в него элементы, отслеживая пространство кучи JVM, используя три вышеуказанных метода:

ArrayList<Integer> arrayList = new ArrayList<>();
System.out.println("i \t Free Memory \t Total Memory \t Max Memory");
for (int i = 0; i < 1000000; i++) {
    arrayList.add(i);
    System.out.println(i + " \t " + Runtime.getRuntime().freeMemory() + 
      " \t \t " + Runtime.getRuntime().totalMemory() + 
      " \t \t " + Runtime.getRuntime().maxMemory());
}

// ...
Output:
i 	   Free Memory 	   Total Memory 	 Max Memory
0 	     254741016 	 	 257425408 	 	 3817865216
1 	     254741016 	 	 257425408 	 	 3817865216
...
1498 	 254741016 	 	 257425408 	 	 3817865216
1499 	 253398840 	 	 257425408 	 	 3817865216
1500 	 253398840 	 	 257425408 	 	 3817865216
...
900079 	 179608120 	 	 260046848 	 	 3817865216
900080 	 302140152 	 	 324534272 	 	 3817865216
900081 	 302140152 	 	 324534272 	 	 3817865216
...

Строка 1498: Значение Runtime#freeMemory уменьшается, когда в куче Java выделяется достаточно места для объектов. Строка 900080: на данный момент JVM имеет больше свободного места, так как сборка мусора запущена, поэтому значения Runtime#freeMemory и Runtime#totalMemory увеличиваются.

Ожидается, что показанные выше значения будут разными при каждом запуске приложения Java.

4. Настройка параметров памяти

    Мы можем переопределить значения по умолчанию для параметров памяти JVM, установив пользовательские значения для определенных флагов при запуске нашей Java-программы для достижения требуемой производительности памяти:

-Xms: значение, присвоенное флагу -Xms, устанавливает начальное и минимальное значение кучи Java. Его можно использовать в тех случаях, когда нашему приложению требуется больше памяти, чем минимум по умолчанию при запуске JVM. -Xmx: Аналогично, мы можем установить максимальное значение для пространства кучи, назначив его флагу -Xmx. Его можно использовать, когда мы хотим ограничить объем памяти, который будет использовать наше приложение, намеренно.

Также обратите внимание, что значение -Xms должно быть меньше или равно значению -Xmx.

java -Xms32M -Xmx64M Main                                                                                        
Free Memory   : 31792664 bytes
Total Memory  : 32505856 bytes
Max Memory    : 59768832 bytes

java -Xms64M -Xmx64M Main
Free Memory   : 63480640 bytes
Total Memory  : 64487424 bytes
Max Memory    : 64487424 bytes

java -Xms64M -Xmx32M Main                                                                                        
Error occurred during initialization of VM
Initial heap size set to a larger value than the maximum heap size

4.1. Использование

5. Заключение

В этой статье мы рассмотрели, как получить метрики памяти JVM через класс Runtime. Эти методы могут быть полезны при расследовании утечек памяти JVM и других проблем, связанных с производительностью памяти JVM.