Рассмотрим следующий класс Java:
public class Mem {
public static void main(final String[] args) {
printMem();
final byte[] bytes = new byte[Integer.parseInt(args[0])];
printMem();
}
private static void printMem() {
System.gc();
final Runtime runtime = Runtime.getRuntime();
final long free = runtime.freeMemory();
final long total = runtime.totalMemory();
final long used = total - free;
final long max = runtime.maxMemory();
System.out.println(String.format(
"Free: %,d; Used: %,d; Total: %,d; Max: %,d",
free, used, total, max));
}
}
А вот выходные данные для двух разных размеров байтового массива:
$ java -Xmx1g Mem 700000000
Free: 250,063,176; Used: 1,595,064; Total: 251,658,240; Max: 954,728,448
Free: 92,445,200; Used: 700,278,256; Total: 792,723,456; Max: 954,728,448
$ java -Xmx1g Mem 800000000
Free: 250,063,176; Used: 1,595,064; Total: 251,658,240; Max: 954,728,448
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Максимальная доступная память составляет около 950 МБ.Я могу выделить массив 700 МБ, но не массив 800 МБ.Я предполагаю, что пространство кучи соответствует подавляющему большинству этих 950 МБ, но я не могу выделить массив 800 МБ, поскольку свободное пространство в куче не обязательно должно быть непрерывным.
В более сложном приложении с максимальной памятью 7,5 ГБ, Я получаю OutOfMemoryError при выделении массива 500 МБ, несмотря на то, что используется всего 2 ГБ.
Есть ли способ предсказать, что определенное выделение памяти вызовет OutOfMemoryError до того, как это произойдет?
ОБНОВЛЕНИЕ Вопрос был помечен как дубликат Проверьте, достаточно ли памяти, прежде чем выделять байтовый массив .Однако в этих двух вопросах есть существенные различия.
- Заключение выделения в блок try-catch для меня не вариант.Я не контролирую распределение.Я могу просто написать что-то вроде плагина для существующего Java-приложения.
- Я не могу избежать выделения больших объектов.
- В указанном вопросе предлагается вызвать
Runtime.getRuntime().freeMemory()
, но пример в моем вопросе показывает, чторезультат такого звонка крайне ненадежен.Во-первых, приложение может получить гораздо больше памяти, если total < max
.Во-вторых, выделение может быть неудачным, даже если кажется, что свободной памяти гораздо больше, чем я выделяю.