Comments 96
Вроде не хватает главного: замера производительности какого-нибудь быстроиграющего, но интенсивного консольного приложения с обычным сборщиком и Эпсилоном. Ну, например YUI Compressor.
-XX:ExitOnOutOfMemoryError
http://www.oracle.com/technetwork/java/javase/8u92-relnotes-2949471.html
Как вы справедливо заметили, джава и стабильность не очень сочетаются.
Что-то у меня есть подозрение, что это в немалой степени зависит от того, что вы делаете и как вы делаете. Java действительно не для всего подходит, но если не мудрить с динамической загрузкой а-ля apache servicemix — работает программа предсказуемо и надёжно...
@Scf
-XX:ExitOnOutOfMemoryError
http://www.oracle.com/technetwork/java/javase/8u92-relnotes-2949471.html
А что делать со старыми версиями? И вы уверены, что GC не будет пытаться прочистить (и тормозить систему), а сразу отдаст OOME? Здесь-то речь именно о fail-fast — даже не пытаться прочистить, а сразу падать.
Или у вас его готовить умеет кто-то или просто повезло. Чуть что-то неожиданное хочешь сделать и возникает проблема — становится непонятно куда копать и что ковырять.
Конечно же, OSGI это не самый простой случай для GC и вообще, хотя бы потому, что это контейнер, и там могут быть внутри приложения с разными паттернами потребления памяти.
Но никакой магии там в общем-то нет. Совершенно. Не больше чем в любом другом контейнере. Я бы сказал, что единственная проблема servicemix — в том что там баги поздно фиксятся по сравнению с теми оригинальными компонентами, из которых он состоит (т.е. karaf, camel, и прочая).
У нас этих кто-то человек 10 наберется.
Ну вот это вас сильно выручает… а у нас — начали ковыряться а опыта ни у кого нет… в итоге — фича не встаёт толком, не обновляется и сидишь недоумеваешь над документацией… которой особо нет, в дебаге, который показывает странное бесконечное циклирование на поиске зависимости для этой фичи… при этом в список каким-то образом пробралась сама эта фича… я так и не разобрался как такую беду пождать...
Могу тут только посоветовать пообщаться на форумах, возможно даже не servicemix, а просто karaf — там народ вполне отзывчивый, мне неоднократно помогали советами.
И кроме шуток — поставьте веб консоль. hawtio или хотя бы родную от карафа. Сильно помогает одним взглядом окинуть, что там на самом деле стоит, и в каком состоянии, и что с чем может конфликтовать. Меня тоже не раз выручало.
А вот что касается стабильности платформы, то я полагаю некоторые деятели из каких-нибудь больших данных и распределённых вычислений с вами бы поспорили. Впрочем даже такие споры в конце концов сведутся не к самой платформе, а к требованиям самого процесса разработки, ибо любая платформа стабильна, если она зависит от измеримых показателей и статистически постоянна.
Пока никаких четких аргументов в сторону не стабильности Java не было. Не могли бы вы привести парочку?
А вот примеров нестабильности не связанных с памятью я не знаю. Может просто потому, что я ещё не всех монстров повидал. Наверняка есть сырые платформы которые и работают ещё кое-как, но я ими не пользуюсь.
В этом случае память ещё не занята, но выделить память для обработки у вас уже не получитсяЭто присутствует, но вы не сказали самого важного: перед тем как бросить OOM будет произведен FullGC 2-3 раза, и если после этого не будет свободной памяти — вылетит OOM (но это еще не конец жизни jvm).
Есть ли подход более правильным с вашей точки зрения? Если есть, думаю, это было бы полезно узнать всем.
Во-вторых, что мешает перехватить OOM и освободить ресурсы или корректно завершить работу того участка, в котором возникла эта ошибка и возможно даже спасти всю программу?
jvm позволяет перехватывать ООМ и «спасать» от падения, вопрос — стоит ли это усилий? Если да — без проблем: перехватывай, спасай от смерти! :)
вот только если не хватает памяти, то тут скорее всего утечка памяти, и спасать по большей части нету смысла — все равно упадет, а потом снова и снова и снова, будет жить в конвульсиях: и сделать ничего не сделает и не упадет / не перезапустится.
По этому никто и не перехватывает ООМ.
не в том смысле что вы ловите и в catch выводите ошибку на экран, а именно обрабатываете, запускаете выгрузку каких то своих данных и запускаете повтор сфейлившейся операции?
Я не уверен, в этой ситуации хотя бы тупо сдампить всю память процесса на диск можно, не создавая новых объектов в куче?
Можно держать baloon и освобождать его, когда память начинает заканчиваться, как вариант. Или, ещё лучше, заранее выделить все необходимые для обработки ошибки объекты.
И это не шутки, а стандартный путь для всяких встроенных «пылесосов» и всего такого. Тут ещё такой момент, что это решает большинство проблем с ДДОСом. Ваш пакет не лезет в буфер? Ну, получите стандартный TCP-отлуп. Но на работе девайса это не скажется.
Память да, конструкторы — нет, т. к. в них могут захватываться другие ресурсы. Но ограниченные буфферы, количество примитивов ОС (если она есть) и отсутствие malloc'а в embedded мире вполне понятная практика.
В Java Card конструкторы вызываются при установке приложения. Как и в персистентных ОС.
Согласен, это пример managed окружения, где объект является единицей деплоя и почти вся память персистентна. Апплет стартует сразу, при установке, так что это тоже укладывается в озвученное vanxant.
Я скорее подразумевал не такое управляемое окружение, а bare metal C/C++ с выделение глобальных статических структур на этапе компиляции: всяких структур описания потоков, mutex/semaphore/condition, буферов данных, сетевых буферов, предпосчитанных заголовков и тому подобных разлечений, чтобы не тащить динамическое управление памятью и его проблемы во встроенное ПО.
чтобы собирать мусор лучше упасть, а умные балансировщики разбалансируют нагрузку по другим нодам/VM
… которые тоже упали
- Циклические ссылки всё равно нужно искать путём сканирования всех объектов в памяти;
- Увеличение/уменьшение счётчика ссылок происходит очень часто, что приводит к частым cach miss даже если поля объекта не менялись;
- В многопоточной среде могут возникнуть race condition из-за того, что операция инкремента/декремента не атомарная. В Python это решено с помощью GIL. Замена на атомарный инкремент/декремент сильно ухудшает общую производительность;
- При уничтожении объекта могут использоваться деструкторы. А так как объект может быть уничтожет в любой момент, то и паузы вызванные деструктором совершенно непредсказуемы;
Ну и самое главное: нельзя просто так поменять один тип управления памятью на другой. Это повлияет на все аспекты работы виртуальной машины. Поэтому в Java не появится Reference counting, а Python врядли перейдёт на Tracing garbage collection.
Проблема атомарного инкремента — не в том, что он делается медленно, а в том, что он требует эксклюзивного доступа. Если не выделить ему отдельную кеш-линию — он будет мешать общему доступу на чтение к другим полям объекта.
А кеш-линия — это, вообще-то, целых 64 байта...
IMHO, aтомарный инкремент/декремент на современных процессорах достаточно быстро делается.Я попытался найти нормальный benchmark для сравнения производительности (ведь сам А. Шипилёв говорил, что нельзя верить бенчмаркам :), нашёл два:
- Comparing the performance of atomic, spinlock and mutex — статья 2012 года, в которой Atomic тест проигрывает No synchronization тесту в 5 раз.
- Comparison: Lockless programming with atomics in C++ 11 vs. mutex and RW-locks — более развёрнутая статья 2015 года, в которой тест #4: Atomic Read & Write проигрывает тесту #0: Unlocked в полтора раза.
А во вторых, хочу обратить ваше внимание на проект Gilectomy, в рамках которого программист Larry Hastings пытается избавиться от Python GIL. Вот его выступление на PyCon 2016: Larry Hastings — The Gilectomy. Чтобы не тратить время, перемотайте на сравнение производительности 25 мин 46 сек. Графики показывают что на текущий момент Python с вырезанным GIL работает в 10-18 раз хуже (в зависимости от количества ядер CPU) чем стандартный Python. И львиная доля падения производительности связанна именно с cache miss-ами.
Отлично, теперь ява может выживать 24/7/362 на терабайтном суперсервере!
// topic mode off
Как будто это новость.
Действительно, интереснее было бы узнать, что выгоднее: перезапускать всю JVM или сделать полную сборку на гигантской куче обычным GC.
ява может выживать 24/7/362
Весьма тонко.
Напомнило PHP, Composer и GC. Верной дорогой идёте, товарищи.
Это и на хабре обсуждалось: https://habrahabr.ru/post/244825/
Ждём когда появится JEP на внедрение RAII, типов-смартпоинтеров и отделения ссылочности от типа :)
Там где аптайм не критичен а важнее отзывчивость — вполне себе решение.
А так то забавно конечно. ПХП учится не умирать и уже вполне стабильно может жить в виде демона, а java учится умирать).
Т.е. пока в OldGen есть место- живём.
Кончилось вместо fullGC- рестарт.
Ну почему же? У многих выходило. Понятно что платой за это обычно будет тупо перерасход памяти, но отключить GC настройками, если вы примерно представляете потребление памяти в своем приложении — не такой уж сложный фокус.
Я не java программист и думал, что придумали что то новое, ждал технических подробностей, а в итоге вся статья укладывается в предложение — «в java теперь можно GC, но она будет падать».
Не разделяю такого оптимизма по поводу отключения GC.
За 10 секунд работы даже JIT как следует не прогреется.
Почти все (если не все) программы на java написаны так, что постоянно выделяют мелкие объекты. Работа со строками вообще основана на таком частом выделении памяти. Чтобы по-нормальному использовать этот EpsilonGC, нужно всё переписывать (на массивы символов вместо строк?). Не говоря уже о том, что перемещающий сборщик мусора, который позволяет невозбранно жрать гигабайты памяти кусками хоть по гигабайту, (почти) не беспокоясь о фрагментации свободной памяти, — полезная в ряде случаев фича. В общем, отключили самое вкусное.
Полагаю, работа с отключенным GC подходит только для скриптов и тому подобного (ну и для научного интереса, естественно). Ещё для использования этого режима нужна уверенность, что тех выделенных N гигабайт памяти будет достаточно для выполнения задачи (если не хватит — задача вообще не выполнится, а с GC выполнилась бы, но медленнее).
Во-вторых, для истинно байтоебских (это термин, а не ругательство!) приложений на Java, такой GC просто незаменим. Представим, что вы пишете прошивку для очередного чайника или умного унитаза, и сам факт сборки мусора считается багом в приложении: вместо того, чтобы собирать мусор лучше упасть, а умные балансировщики разбалансируют нагрузку по другим нодам/VM.
Пример повеселил. Кластер в чайнике — это уже не байтоёбство, а несколько другой вид развлечений.
В принципе, этим gc могут еще банки заинтересоваться с их low-latency системами. Тем более что все необходимые безмусорные библиотеки у них уже есть — от коллекций до io.
А так же непосредственно для разработки библиотек, которые не мусорят — будет проще находить точки генерации мусора.
Но самое главное — это для того, чтобы бенчмарки гонять xD
С точки зрения аналитики и т.п. в джаве всё уже есть — java mission control позволяет смотреть подробнейшую статистику по аллокациям. Вот если оно меньше памяти потребляет или быстрее работает...
Насколько помню, при разработке лицензия разрешает его использовать:
The Java Flight Recorder (JFR) is a commercial feature. You can use it for free on developer desktops/laptops, and for evaluation purposes in test, development, and production environments. However, to enable JFR on a production server, you require a commercial license. Using JMC UI for other purposes on the JDK does not require a commercial license.
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr002.html
Там -XX:+UnlockCommercialFeatures -XX:+FlightRecorder
довольно ясно намекают, что это коммерческая фича.
Ещё народ старательно накалывается с их msi-установщиком (Java SE Enterprise MSI installer), который очень удобно раскатывать через доменные политики. У него тоже в названии "Enterprise", но народ это не останавливало, пока не приходили добрые люди от Oracle.
Но Надо помнить, что суть gc stop заключается в дефрагментации памяти. В языках, где подобной фичи нет — никто никогда память вообще не двигает: нате вам OOM — и гудбай. Не нравится — втыкай еще памяти, или оптимизируй задачу.
Разрабы java заморочились и для этого придумали full gc, который все останавливает на время работы. Сделали они это, вероятно, потому что оно и так много памяти ело. Типа, чтобы на них сильно не кричали. Но люди начали считать эту фичу штатным средством. На самом деле, это не штатное средство, а палочка-выручалочка, дающая то, чтобы оно хоть как-то работало, пока ты побежал в магазин докупать память. Если до него дошло дело, это лишь значит, что для реализации данного алгоритма мало памяти, и по хорошему ты должен сказать спасибо, что оно не ooэмнулось а хоть как-то худо-бедно отработало.
Хотя в некоторых задача — да, лучше бы оно ооэмалось.
Другое дело, что актуально ли это на задачах, для которых он нужен.
Это у него штатная возможность, которую кто-то поди использует — говорят, еще быстрее работает.
Это для серверных приложений — Представьте себе n машин, на которых периодически жестко падают процессы, а перед ними — балансер, который умеет делать перезапрос при ошибке.
Представьте себе, что балансер тоже работает по такому же принципу: падает каждые 10000 запросов.
Именно! В этом и смысл облака — что балансер тоже может упасть, поэтому балансеров должно быть два, а поиск балансеров должен работать через другую отказоустойчивую систему… DNS к примеру.
Отвечая на вопрос: и dns-ресолверы ведут себя так же.
Представьте себе мир, в котором всё построено на софте, разработчики решили, что падать из-за того, что закончилась write-once память — это норма. А GC — это для лохов.
Что-то совсем не похоже.
Практическая полезность была бы кстати, если бы JVM умела бы делать быстрый hot-restart: прибиваются все треды, освобождаются все системные ресурсы, но при этом оставлялся бы PermGen с классами, сгенеренной статистикой выполнения и предкомпилированным кодом.
Предлагаю следующий этап эволюции GC и архитектуры приложений: не собирать мусор, пока не заполнится вся память, затем вызвать специальный OutOfMemory-хандлер у тредов, у которых он зарегистрирован, после чего начать полную сборку мусора.
Что это даст? Процессинговые треды, имеющие OutOfMemory хандлер смогут обработать ситуацию: закрыть ресурсы, вернуть ошибку клиенту, сообщить в кластер, что нода отвалилась, и при необходимости рестартнуть после сборки мусора. Чтобы при вызове хандлеров не было повторного OutOfMemory вся аллокация ведется в отдельно зарезервированной области.
Таким образом можно реализовать быстрый перезапуск процессинга без реальной необходимости перезапуска системы.
Практическая полезность была бы кстати, если бы JVM умела бы делать быстрый hot-restart: прибиваются все треды, освобождаются все системные ресурсы, но при этом оставлялся бы PermGen с классами, сгенеренной статистикой выполнения и предкомпилированным кодом.
Дык, AOT в Java9 будет, и в некоторых кейсах пермгены и все прочее можно будет выкинуть.
AOT + GC Epsilon + не плодить мусор = хардкор для эмбеддед.
Новый GC Epsilon. У джавы может не быть сборки мусора. Шок. Сенсация