-Xmx различия между апплетом и автономным процессом Java

У меня есть апплет, которому требуется больше или меньше памяти, в зависимости от количества данных у клиента.

Обычно мы рекомендуем использовать последнюю версию Java 1.6, но на самом деле мы поддерживаем Java 1.5+, поэтому у нас есть защита в апплете, который показывает диалоговое окно с предупреждением о «нехватке памяти» и инструкциями, куда перейти, чтобы увеличить объем памяти.

Однако я был очень удивлен, увидев, что -Xmx по-разному работает в апплетах и ​​автономных процессах, и я не могу определить, достаточно ли памяти у апплета.

Вот как это делается:

  • the applet receives the following arguments :
    • param name="java_arguments" value="-Xmx153m" (of course this works in Java 1.6 update 10, otherwise it will get 64M in Java 1.5 and Java 1.6 prior update 10)
    • param name = "required.memory" value = "153"
  • во время выполнения мы сравниваем required.memory с Runtime.getRuntime (). maxMemory ()
  • с лимитом 153M в апплете мы получаем 143589376, но в автономном приложении мы получаем 155516928
  • 153 * 1000 * 1000 = 153000000 (на всякий случай я не использую 1024 для 1K), что определенно больше 143589376.

Если я использую коэффициент 0,9, чтобы избежать каких-либо приближений, в JVM кажется, что это работает хорошо, но правильное ли это значение - 0,9? Как они рассчитывают этот предел и почему он отличается в автономных приложениях и апплетах?


person adrian.tarau    schedule 14.07.2009    source источник


Ответы (2)


Пришло время рассказать о памяти Java.

Во-первых, нехватка памяти в Java (т.е. фактическое получение OutOfMemoryError) зависит от особенностей работающего сборщика мусора.

Вопреки тому, что следует из названия, вы можете получить OutOfMemoryError, фактически не исчерпав память; он также выдается, когда среда выполнения решает потратить чрезмерное количество времени на сборку мусора (источник, он там закопан).

Кроме того, вы можете получить OutOfMemoryError, если исчерпаете определенные типы памяти. Помните, что Java GC является сборщиком поколений, и если вам случится исчерпать одно из поколений (я хочу сказать «постоянное», но могу ошибаться), вам также фактически не хватит памяти. Это означает, что у вас может остаться место в куче из представления ОС, но вы не сможете выделить что-либо в куче Java.

Наконец, есть некоторые фактические накладные расходы, связанные с сборщиком мусора, которые могут занимать некоторое пространство кучи.


Более вероятно, что в вашем случае произойдет некий вариант следующего: ваш код работает как в автономном контексте, так и в контексте апплета, каждый контекст имеет свой менеджер безопасности и свое поведение при запуске; это означает, что задействован другой набор классов (которые попадают в постоянное поколение) с разными зависимостями. Я предполагаю, что «стек» апплета толще, учитывая более строгие ограничения на их поведение, и это, вероятно, объясняет большую часть различий в maxMemory ().

Короче говоря, разница в доступной памяти, вероятно, связана с некоторым изменением памяти, зарезервированной средой выполнения Java для своей собственной работы. Это может быть связано с сборщиком мусора, политикой безопасности или просто разными классами, загруженными для среды апплета по сравнению с автономным. Runtime.maxMemory () может также учитывать любое из вышеперечисленных условий «нехватки памяти» при определении того, что возвращать. Соответственно, значение 0,9, вероятно, является побочным эффектом реализации, который может измениться в будущем.

person Kevin Montrose    schedule 15.07.2009

Кевин, действительно имеет смысл отличать работу апплета от настольного приложения, но что меня поразило, так это то, что существует большая разница в максимальной (большей, чем я думал) памяти, доступной между апплетом и настольным приложением, что составляет ~ 8%. Если это, как вы сказали, "стек" апплета "толще, учитывая более строгие ограничения на их поведение", я ожидал, что апплет получит больший максимальный объем памяти, а не автономная версия.

Я измерил расстояние между апплетом и приложением. Оба получили одинаковые параметры (-Xmx128M), оба работают с одной и той же JVM - Java HotSpot (TM) 64-разрядная серверная виртуальная машина версии 11.3-b02 (впервые я подумал, что апплет работает с клиентской JVM, а рабочий стол работает с сервером). JVM, но похоже, что оба они с JVM сервера)

Конечно, на самом деле JVM получили другие параметры, но ничего серьезного (как мне кажется):

  • апплет: -D__jvm_launched = 426431678538 -Xbootclasspath / a: /usr/jvm/64/jdk1.6.0_13/jre/lib/deploy.jar: /usr/jvm/64/jdk1.6.0_13/jre/lib/javaws.jar : /usr/jvm/64/jdk1.6.0_13/jre/lib/plugin.jar -Xmx128m
  • автономный: -Xrunjdwp: transport = dt_socket, address = 127.0.0.1: 54876, suspend = y, server = n -Xmx128M -Dfile.encoding = UTF-8

Аплет: макс. память = 119,314 КБ

  • Heap
    • PS Eden Space : 14,592K
    • PS Survivor Space: 14.528K
    • PS Old Gen : 87.424K
      • Total : 116.544K
  • Non-Heap
    • Mem Pool Code Cache : 49.152K
    • Mem Pool PS Perm Gen : 86.016K
      • Total : 135.168K

Рабочий стол: макс. память = 129,302 КБ

  • Heap
    • PS Eden Space : 8.704K
    • PS Survivor Space: 3.008K
    • PS Old Gen : 116.544K
      • Total : 126.272K
  • Non-Heap
    • Mem Pool Code Cache : 49.152K
    • Mem Pool PS Perm Gen : 65.536K
      • Total : 135.168K

Большие различия между этими двумя JVM

  • PS Perm Gen, апплет получил больший кусок - что имеет смысл, поскольку апплет, вероятно, загрузит дополнительные классы по сравнению с автономной версией (но даже в этом случае "Old Gen" намного меньше, что странно, потому что обычно все эти дополнительные классы со временем попадет в "Старый Ген")
  • Память кучи, совершенно другое соотношение между Eden / Survivor / Old Gen. Старое поколение апплета составляет 75% от старого поколения автономного приложения, это большая разница, я бы сказал, я добр, если ожидаю (почти) той же модели памяти, поскольку не должно Нет никакой разницы, когда я запускаю приложение как апплет или как настольное приложение.

Теперь я еще больше сбит с толку не только из-за того, что я не знаю, как рассчитать максимальное соотношение памяти (действительно, 0,9 не может быть действительным с будущими версиями JVM), но и мое приложение могло выйти из памяти при запуске как апплет. Мне нужно было бы увеличить максимальный объем памяти на ~ 10-15%, когда он работает как апплет, на всякий случай.

Я до сих пор не понимаю, почему такое разное соотношение кучи (на той же машине) и куча меньшего размера (особенно с учетом того, что апплету нужны дополнительные классы).

По каким причинам? Мне любопытно, это вышло за рамки моей потребности проверить, имеет ли апплет максимальный объем памяти, который, по моему мнению, должен.

person adrian.tarau    schedule 15.07.2009