Runtime.freeMemory: примеры (JAVA)
Runtime.freeMemory: longОписание Runtime.freeMemory
Метод Runtime.freeMemory() возвращает приблизительное количество свободной памяти (в байтах) в хипе JVM для текущего процесса. Это экземплярный метод класса java.lang.Runtime, обычно вызываемый как Runtime.getRuntime().freeMemory(). Параметров у метода нет, возвращаемое значение имеет тип long.
Типичные сценарии использования: мониторинг состояния памяти внутри приложения, простые эвристики перед выделением больших структур данных, логирование для дальнейшего анализа. Метод не предназначен для точного учёта доступной памяти операционной системы и не может служить надёжным инструментом для принятия критических решений о выделении памяти.
Описание возвращаемых значений и интерпретация:
- Положительное число (в байтах) - оценка объёма свободного пространства в хипе JVM.
- Ноль - означает, что JVM оценивает свободное пространство как равное нулю; при попытке выделить дополнительную память возможно возникновение
OutOfMemoryError. - Значения изменяются динамически и могут резко уменьшаться или увеличиваться после работы сборщика мусора.
Важные замечания о контексте и соотношениях с другими методами:
Runtime.totalMemory()возвращает текущий размер хипа, выделенный JVM.Runtime.maxMemory()- верхний предел хипа, установленный флагом-Xmx(если неограничен, возвращает максимально доступное значение).- Соотношение обычно представляется как: свободная память ≈
freeMemory(), занято -totalMemory() - freeMemory(), максимально доступно -maxMemory(). Значения отражают только память внутри JVM-управляемого хипа и не учитывают нативные аллокации.
Поведение относительно сборщика мусора: метод возвращает оценку без принудительного запуска GC. После явного вызова System.gc() или по триггеру сборщика мусора значение обычно увеличивается, но вызов GC не гарантирован и может быть проигнорирован JVM.
Примеры вызова Runtime.freeMemory
Ниже приведены простые примеры работы метода. Параметров нет, поэтому все примеры показывают разные сценарии использования и возможные результаты.
1. Базовый вывод свободной памяти
public class FreeMemBasic {
public static void main(String[] args) {
long free = Runtime.getRuntime().freeMemory();
System.out.println("free=" + free + " bytes");
}
}
free=12345678 bytes
2. Изменение значения после выделения массивов
public class FreeMemAllocate {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
System.out.println("before=" + rt.freeMemory());
int[] arr = new int[5_000_000]; // заметное выделение
System.out.println("after alloc=" + rt.freeMemory());
}
}
before=2468101248 after alloc=1876543216
3. Поведение после запроса сборщика мусора
public class FreeMemGc {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
byte[] b = new byte[10_000_000];
System.out.println("after alloc=" + rt.freeMemory());
b = null; // освобождение ссылки
System.gc();
System.out.println("after gc=" + rt.freeMemory());
}
}
after alloc=16000000 after gc=85000000
Похожие API в Java
Несколько способов получить информацию о памяти и их особенности:
Runtime.totalMemory()- показывает текущий объём хипа, выделенный JVM. Совместно сfreeMemory()позволяет вычислить используемую память.Runtime.maxMemory()- верхний предел хипа, полезен для определения резерва перед достижением-Xmx.java.lang.management.MemoryMXBean(черезManagementFactory.getMemoryMXBean()) - возвращает объектMemoryUsageс полямиgetUsed(),getCommitted(),getMax(), что даёт более структурированную информацию о куче и внекучевой памяти.- MemoryPoolMXBean - позволяет получить данные по отдельным пулам памяти (Eden, Survivor, Old Gen) и установить пороги использования.
Когда что предпочтительнее: для простого и быстрого измерения подойдёт Runtime.freeMemory(), а для детального мониторинга и оповещений лучше использовать API из пакета java.lang.management.
Аналоги в других языках и отличия
Короткие примеры и особенности аналогичных функций в популярных языках:
PHP
<?php
echo memory_get_usage();
?>
3619840
Комментарий: возвращает использование памяти скриптом (байты), отличается от JVM: показывает лишь потребление процесса (частично включает нативную память).
Node.js (JavaScript на сервере)
console.log(process.memoryUsage());
{ rss: 21000000, heapTotal: 5300000, heapUsed: 3400000, external: 120000 }
Комментарий: возвращает объект с несколькими полями; heapUsed ближе по смыслу к totalMemory()-freeMemory() в Java.
Python (psutil)
import psutil
p = psutil.Process()
print(p.memory_info().rss)
41943040
Комментарий: показывает резидентный размер процесса в байтах; для оценки управляемой памяти внутри интерпретатора понадобятся другие инструменты (tracemalloc).
C# (.NET)
using System;
class P { static void Main(){ Console.WriteLine(GC.GetTotalMemory(false)); }}
12345678
Комментарий: GC.GetTotalMemory возвращает оценку используемой управляемой памяти; близко по смыслу к данным Java.
Go (Golang)
package main
import ("fmt" "runtime")
func main() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Println(m.Alloc)
}
12345678
Комментарий: предоставляет подробную статистику (Alloc, HeapSys, HeapAlloc и т. п.).
Kotlin
fun main() {
println(Runtime.getRuntime().freeMemory())
}
12345678
Комментарий: Kotlin использует JVM API, поэтому поведение идентично Java.
Lua
print(collectgarbage("count")) -- возвращает КБ
5.3
Комментарий: возвращает объём управляемой Lua-памяти в килобайтах; не даёт детальной картины системной памяти.
SQL (общая заметка)
-- PostgreSQL, пример размера базы
SELECT pg_database_size(current_database());
104857600
Комментарий: SQL-серверы возвращают информацию о размерах баз/таблиц, а не об объёме свободной оперативной памяти процесса; прямого аналога freeMemory() в SQL обычно не требуется.
Типичные ошибки при использовании
Ниже приведены распространённые ошибки и примеры, демонстрирующие подводные камни.
1) Ошибка в интерпретации: ожидание, что value отражает свободную память ОС
// Обычная ошибка: считать, что return из freeMemory() - свободная память всей системы
long free = Runtime.getRuntime().freeMemory();
System.out.println("free system memory=" + free);
free system memory=12345678
Комментарий: значение отражает свободное пространство внутри хипа JVM, а не свободную оперативную память ОС.
2) Приведение к int и переполнение
public class CastProblem {
public static void main(String[] args) {
long free = Runtime.getRuntime().freeMemory();
int f = (int) free; // возможное переполнение
System.out.println(f);
}
}
-1234567890
Комментарий: при больших значениях явное приведение к int может привести к отрицательному числу из-за переполнения.
3) Надежда на немедленный эффект от System.gc()
Runtime.getRuntime().gc();
long after = Runtime.getRuntime().freeMemory();
System.out.println(after);
12345678
Комментарий: вызов System.gc() не гарантирует немедленное или полное выполнение сборки мусора, поэтому ожидание предсказуемого увеличения freeMemory() может оказаться неверным.
4) Использование значения для принятия критических решений
Привязка логики приложения к числу байт, возвращаемых freeMemory(), без учета maxMemory(), нативных аллокаций и поведения GC часто приводит к ошибкам и неожиданному OOM.
Изменения и заметки по версиям Java
Метод Runtime.freeMemory() существует в API Java длительное время и в последних версиях не подвергался удалению или депрекации. Семантика метода остаётся прежней: оценка свободного пространства в хипе. В современных релизах JVM улучшилась телеметрия и инструменты управления памятью (улучшенные средства профилирования, JFR, расширенный API java.lang.management), поэтому для комплексного мониторинга чаще рекомендуется использовать MemoryMXBean и соответствующие JFR-события.
Расширенные и редкие варианты использования
Несколько более сложных сценариев с пояснениями.
1. Мониторинг памяти в отдельном потоке и логирование трендов
import java.util.concurrent.*;
public class MemoryMonitor {
public static void main(String[] args) throws Exception {
ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
Runnable task = () -> {
Runtime rt = Runtime.getRuntime();
long free = rt.freeMemory();
long total = rt.totalMemory();
long max = rt.maxMemory();
System.out.println("free=" + free + " total=" + total + " max=" + max);
};
s.scheduleAtFixedRate(task, 0, 2, TimeUnit.SECONDS);
Thread.sleep(7000);
s.shutdown();
}
}
free=2468101248 total=3040870400 max=3817865216 free=2459000000 total=3040870400 max=3817865216 free=2400000000 total=3040870400 max=3817865216
Комментарий: такой мониторинг позволяет выявлять постепенное уменьшение свободной памяти и служит для предсказания утечек.
2. Эвристика дефрагментации перед крупным выделением
public class HeuristicAlloc {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
long freeBefore = rt.freeMemory();
if (freeBefore < 50_000_000L) {
System.gc(); // попытка освободить
}
// затем повторная проверка
System.out.println("free now=" + rt.freeMemory());
}
}
free now=120000000
Комментарий: эвристика может помочь, но полагаться на неё как на гарантию безопасного выделения нежелательно.
3. Детектирование утечек через минимальное наблюдаемое значение
import java.util.*;
class LeakFinder {
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
long min = Long.MAX_VALUE;
for (int i = 0; i < 10; i++) {
List holder = new ArrayList<>();
for (int j = 0; j < 50; j++) holder.add(new byte[200_000]);
long free = rt.freeMemory();
min = Math.min(min, free);
System.out.println(i + ": free=" + free);
// убрать ссылки
holder = null;
System.gc();
Thread.sleep(200);
}
System.out.println("min observed free=" + min);
}
}
0: free=18000000 1: free=17000000 2: free=16000000 min observed free=16000000
Комментарий: при постепенном снижении минимального значения может возникнуть подозрение на утечку, но для подтверждения требуется профайлинг.
4. Комбинация с MemoryPoolMXBean для пороговых уведомлений
// Фрагмент: регистрация слушателя для пула старого поколения
// (Код сокращён; в реальном коде требуется обработка Notification and Binding)
import java.lang.management.*;
import javax.management.*;
// Получение пула и установка порога используется для получения уведомлений о росте использования
(в реальном окружении будет выведено уведомление при достижении порога использования)
Комментарий: использование MemoryPoolMXBean даёт более гибкие уведомления и позволяет реагировать на специфичные события хипа.
5. Пример, демонстрирующий влияние -Xmx и -Xms
// Запуск: java -Xms256m -Xmx512m MemTest
public class MemTest {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
System.out.println("total=" + rt.totalMemory() + " max=" + rt.maxMemory());
System.out.println("free=" + rt.freeMemory());
}
}
total=268435456 max=536870912 free=250000000
Комментарий: значения зависят от настроек JVM и помогают планировать выделения под конкретные условия запуска.