Runtime.freeMemory: примеры (JAVA)

Доступная память приложения под Java
Раздел: Работа с процессами и памятью (Runtime, Process)
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. Мониторинг памяти в отдельном потоке и логирование трендов

Пример java
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. Эвристика дефрагментации перед крупным выделением

Пример java
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. Детектирование утечек через минимальное наблюдаемое значение

Пример java
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 для пороговых уведомлений

Пример java
// Фрагмент: регистрация слушателя для пула старого поколения
// (Код сокращён; в реальном коде требуется обработка Notification and Binding)
import java.lang.management.*;
import javax.management.*;

// Получение пула и установка порога используется для получения уведомлений о росте использования
(в реальном окружении будет выведено уведомление при достижении порога использования)

Комментарий: использование MemoryPoolMXBean даёт более гибкие уведомления и позволяет реагировать на специфичные события хипа.

5. Пример, демонстрирующий влияние -Xmx и -Xms

Пример java
// Запуск: 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 и помогают планировать выделения под конкретные условия запуска.

джава Runtime.freeMemory function comments

En
Runtime.freeMemory Returns the amount of free memory in the Java Virtual Machine