Runtime.totalMemory: примеры (JAVA)
Runtime.totalMemory: longОписание
Метод Runtime.totalMemory() возвращает текущий размер кучи, выделенной виртуальной машиной Java, в байтах. Формально это значение отражает суммарный объём памяти, доступный JVM для размещения объектов в данный момент; оно обычно равно сумме занятой и свободной памяти внутри кучи: totalMemory = used + free.
Сигнатура метода: public long totalMemory(). Аргументы отсутствуют. Возвращаемое значение имеет тип long и выражается в байтах. Значение не бросает проверяемых исключений и всегда неотрицательно.
Когда применяется: для быстрой оценки текущего объёма кучи, логирования состояния памяти, простого мониторинга и вычисления используемой памяти (в паре с Runtime.freeMemory()). Не подходит для точного профилирования: для детальной информации рекомендуется использовать API из java.lang.management и специализированные профайлеры.
Особенности поведения:
- Возвращаемая величина может динамически изменяться в процессе работы программы: JVM может расширять или сокращать кучу (в зависимости от настроек -Xms, -Xmx и поведения GC).
- totalMemory не обязана быть равна maxMemory.
maxMemory()задаёт верхнюю границу кучи, тогда как totalMemory показывает текущий выделенный размер. - Значение зависит от используемого сборщика мусора и параметров JVM; поведение может отличаться между версиями Java и разными реализациями JVM.
// Простой вызов в Java
Runtime rt = Runtime.getRuntime();
long total = rt.totalMemory();
long free = rt.freeMemory();
long used = total - free;
System.out.println("total=" + total + " bytes, used=" + used + " bytes");
total=268435456 bytes, used=12345678 bytes
Короткие примеры
Ниже представлены простые варианты использования totalMemory в типичных ситуациях. Приведённый вывод - примерный и зависит от конфигурации JVM.
1) Базовый вывод значений памяти и перевод в мегабайты.
public class Example1 {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
long total = rt.totalMemory();
long free = rt.freeMemory();
long used = total - free;
System.out.println("total bytes: " + total);
System.out.println("used bytes: " + used);
System.out.println("total MB: " + (total / 1024 / 1024) + " MB");
}
}
total bytes: 268435456 used bytes: 12582912 total MB: 256 MB
2) Наблюдение за влиянием -Xmx. Запуск с флагом -Xmx64m демонстрирует ограничение максимаума; totalMemory может быть меньше или равен maxMemory.
// Запуск: java -Xmx64m Example2
public class Example2 {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
System.out.println("total=" + rt.totalMemory() + " bytes");
System.out.println("max=" + rt.maxMemory() + " bytes");
}
}
total=33554432 bytes max=67108864 bytes
3) Влияние вызова сборки мусора на freeMemory и totalMemory.
public class Example3 {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
byte[] a = new byte[10_000_000]; // занимает ~10MB
System.out.println("before GC: total=" + rt.totalMemory() + ", free=" + rt.freeMemory());
a = null;
System.gc();
System.out.println("after GC: total=" + rt.totalMemory() + ", free=" + rt.freeMemory());
}
}
before GC: total=67108864, free=4800000 after GC: total=67108864, free=61000000
Похожие API в Java
В Java есть несколько инструментов, дающих похожую или более детальную информацию о памяти:
- Runtime.freeMemory() - возвращает объём свободной памяти в текущей выделенной куче. Часто используется вместе с totalMemory для вычисления used.
- Runtime.maxMemory() - верхняя граница кучи (обычно связана с -Xmx). Полезна для проверки лимита, в отличие от текущего выделенного размера.
- MemoryMXBean (java.lang.management.ManagementFactory.getMemoryMXBean()) - предоставляет структуру MemoryUsage с полями init, used, committed, max для хипа и non-heap, более точная для мониторинга.
- MemoryPoolMXBean - позволяет смотреть по пулам памяти (Eden, Survivor, Old Gen) и выбирать более точные метрики.
Рекомендации по выбору: для простых проверок и быстрой диагностики подходит Runtime.totalMemory вместе с freeMemory и maxMemory. Для промышленных мониторингов и алертинга предпочтительнее ManagementFactory и специализированные бенчмарки и профайлеры.
Аналоги в других языках
Краткие аналоги и отличия от Java totalMemory в разных языках с примерами.
- PHP:
memory_get_usage()иmemory_get_peak_usage(). Возвращают используемую PHP-процессом память в байтах. Это процессная метрика, не отражает кучу JVM.<? echo memory_get_usage() . " bytes\n"; ?>1234567 bytes
- JavaScript (Node.js):
process.memoryUsage()возвращает объект с heapTotal, heapUsed и rss. heapTotal похож на totalMemory.// Node.js console.log(process.memoryUsage());{ rss: 23191040, heapTotal: 5767168, heapUsed: 3324552, external: 12345 } - Браузер JS:
performance.memory(не стандартно поддерживается во всех браузерах) предоставляет похожие поля. - Python: нет встроенного прямого аналога к JVM-куче; используются модуль
psutilдля процесса илиtracemallocдля слежения за аллокациями.import psutil, os p = psutil.Process(os.getpid()) print(p.memory_info().rss)2345678
- SQL: в стандартном SQL нет понятия JVM-кучи; можно использовать средства СУБД для просмотра потребления памяти сервера (например, PostgreSQL: pg_stat_activity или внешние инструменты).
- C#:
GC.GetTotalMemory(false)возвращает количество байт, занятой управляемой памятью. Поведение похоже, но учитывает модель CLR.using System; class P { static void Main(){ Console.WriteLine(GC.GetTotalMemory(false)); }}8765432
- Lua:
collectgarbage("count")возвращает килобайты занятой памяти Lua-станции.print(collectgarbage("count"))52.3
- Go (Golang): пакет
runtimeи структураruntime.MemStatsдают подробные метрики, в том числе HeapAlloc и HeapSys.package main import ( "fmt" "runtime" ) func main(){ var m runtime.MemStats; runtime.ReadMemStats(&m); fmt.Println(m.HeapSys) }524288
- Kotlin: использует ту же JVM, что и Java, поэтому применяется Runtime.getRuntime().totalMemory() и прочие Java-методы непосредственно.
Отличия: многие языки дают метрики уровня процесса или аллокатора конкретной среды выполнения. Java totalMemory - показатель внутренней кучи JVM, не напрямую сопоставимый с системным RSS без дополнительных преобразований.
Типичные ошибки
Частые заблуждения и ошибки при использовании totalMemory:
- Путаница totalMemory и maxMemory. Первый - текущий выделенный объём, второй - верхняя граница. Пример ошибки: ожидание, что total всегда равен max.
- Неправильная интерпретация единиц. Метод возвращает байты; частая ошибка - деление с потерей точности при использовании целочисленного деления в неправильной последовательности.
- Ожидание немедленного уменьшения totalMemory после System.gc(). GC может освободить объём внутри текущей кучи (увеличив freeMemory), но JVM не обязана уменьшать totalMemory.
- Использование int для хранения результата. Возвращаемое значение long - приведение к int может вызвать переполнение на больших кластерах.
Пример ошибки с целочисленным делением:
Runtime rt = Runtime.getRuntime();
int totalMB = (int)(rt.totalMemory() / 1024 / 1024); // OK
int bad = (int)(rt.totalMemory() / (1024 * 1024)); // тоже OK но при 32-битном int возможен overflow позже
System.out.println(totalMB);
256
Пример неверного ожидания уменьшения totalMemory после GC:
Runtime rt = Runtime.getRuntime();
// при больших аллокациях
System.gc();
System.out.println("total after GC: " + rt.totalMemory());
total after GC: 67108864
Комментарий: значение total может остаться 67108864, хотя freeMemory выросла.
Изменения в последних версиях Java
Метод totalMemory существует в Java с ранних версий и сохранил свою сигнатуру и семантику. Прямых изменений в контракте метода не происходило. Однако поведение управления кучей могло измениться в новых версиях JVM и при внедрении новых сборщиков мусора (G1, ZGC, Shenandoah), что влияет на динамику изменения totalMemory и на стратегию расширения/сжатия кучи.
Кратко: API стабилен, но наблюдаемое значение может отличаться в зависимости от версии JVM и выбранного GC.
Расширенные примеры
Несколько подробных сценариев применения totalMemory в сочетании с другими инструментами.
1) Отслеживание утечек через периодические снимки памяти:
public class LeakDetector {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
for (int i = 0; i < 10; i++) {
System.gc();
Thread.sleep(500);
long used = rt.totalMemory() - rt.freeMemory();
System.out.println(i + ": used=" + (used / 1024 / 1024) + " MB, total=" + (rt.totalMemory() / 1024 / 1024) + " MB");
// эмулировать нарастание занятой памяти
byte[] b = new byte[5_000_000];
}
}
}
0: used=20 MB, total=256 MB 1: used=25 MB, total=256 MB ... (прогресс) ... 9: used=70 MB, total=256 MB
Комментарий: наблюдение динамики used и total позволит заметить устойчивый рост used при постоянном увеличении retained объектов.
2) Принятие решения об отложленной загрузке компонентов, если свободная память мала:
public class LazyLoadPolicy {
public static boolean canLoadLargeModule() {
Runtime rt = Runtime.getRuntime();
long free = rt.freeMemory();
long total = rt.totalMemory();
long max = rt.maxMemory();
long availableToGrow = max - total + free; // сколько ещё можно безопасно использовать
return availableToGrow > (50L * 1024 * 1024); // требование 50MB
}
}
true
Пояснение: расчёт availableToGrow учитывает и текущий свободный буфер, и возможное расширение кучи до maxMemory.
3) Сравнение данных Runtime с MemoryMXBean для валидации:
import java.lang.management.*;
public class CompareMemory {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
long rtTotal = rt.totalMemory();
long heapCommitted = mbean.getHeapMemoryUsage().getCommitted();
System.out.println("rt.total=" + rtTotal + ", mbean.committed=" + heapCommitted);
}
}
rt.total=268435456, mbean.committed=268435456
Пояснение: committed в MemoryUsage соответствует объёму памяти, выделенному под хип и аналогично totalMemory в большинстве реализаций JVM.
4) Замер кратковременного потребления при нагрузочном тесте:
public class LoadSpike {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
long before = rt.totalMemory() - rt.freeMemory();
byte[][] arrays = new byte[200][];
for (int i = 0; i < arrays.length; i++) arrays[i] = new byte[200_000]; // ~200KB * 200 ~40MB
long after = rt.totalMemory() - rt.freeMemory();
System.out.println("delta MB: " + ((after - before) / 1024 / 1024));
}
}
delta MB: 38
Комментарий: в продакшн-сценариях подобные замеры помогают определить влияние определённых операций на использование кучи.