Низкая производительность или высокие накладные расходы из-за вызовов System.gc()

Проблема

Накладные расходы на сборку мусора могут быть довольно высокими, или на производительность может повлиять частая сборка мусора из-за пользовательских запросов от вызовов System.gc().

Симптом

Высокие накладные расходы на сборку мусора в случаях, когда куча не страдает сбоями выделения.

Причина

Код приложения вызывает System.gc();

Диагностика проблемы

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

Решение проблемы

Чтобы снизить нагрузку на производительность, введите следующий общий аргумент JVM:

-Xdisableexplicitgc

Подробные сведения об общих аргументах JVM см. в этой технической заметке
«Настройка общих аргументов JVM в WebSphere Application Server» http://www.ibm.com/support/docview .wss?rs=180&uid=swg21417365 Чтобы идентифицировать вызовы из кода приложения, которые выдают явные запросы на сборку мусора, введите следующий параметр -Xtrace в качестве общего аргумента JVM: -Xtrace:print=mt,methods={java/lang /System.gc}, триггер = метод {java/lang/System.gc, jstacktrace}

Xtrace будет регистрировать вызовы методов в файле native_stderr.log. Трассировка покажет вызовы даже с включенным параметром -Xdisableexplicitgc. Трассировку стека следует использовать для поиска источника явных запросов на сборку мусора в коде приложения.

После обновления кода приложения для удаления явных запросов на сборку мусора удалите упомянутые выше универсальные аргументы JVM

Java. System.gc(); Эффективность.

После ответа на вопрос о том, как принудительно освобождать объекты в Java (парень очищал HashMap размером 1,5 ГБ) с помощью System.gc(), мне сказали, что вызывать System.gc() вручную — плохая практика, но комментарии не были вполне убедительно. Вдобавок, похоже, никто не осмелился проголосовать ни за, ни против моего ответа.

Мне там сказали, что это плохая практика, но потом мне также сказали, что запуски сборщика мусора больше не останавливают мир систематически, и что JVM также может эффективно использовать его только как подсказку, так что я вроде как в убыток.

Я понимаю, что JVM обычно лучше вас знает, когда ей нужно освободить память. Я также понимаю, что беспокоиться о нескольких килобайтах данных глупо. Я также понимаю, что даже мегабайты данных уже не те, что были несколько лет назад. Но все же, 1,5 гигабайта? И вы знаете, что в памяти висит около 1,5 ГБ данных; это не похоже на выстрел в темноте. Является ли System.gc() систематически плохой или есть какой-то момент, когда все становится хорошо?

Так что вопрос на самом деле двойной:

Почему вызов System.gc() является плохой практикой? Это действительно просто намек на JVM в определенных реализациях или это всегда полный цикл сбора? Существуют ли действительно реализации сборщиков мусора, которые могут выполнять свою работу, не останавливая мир? Пожалуйста, пролейте свет на различные утверждения, сделанные людьми в комментариях к моему ответу.
Где порог? Никогда не стоит вызывать System.gc() или бывают случаи, когда это допустимо? Если да, то какие это времена?

Причина, по которой все всегда говорят избегать System.gc(), заключается в том, что это довольно хороший индикатор фундаментально неработающего кода. Любой код, корректность которого зависит от него, безусловно, неисправен; любые, которые полагаются на него для производительности, скорее всего, сломаны.

Вы не знаете, под каким сборщиком мусора вы работаете. Конечно, есть некоторые, которые не «останавливают мир», как вы утверждаете, но некоторые JVM не такие умные или по разным причинам (возможно, они на телефоне?) этого не делают. Вы не знаете, что это будет делать.

Кроме того, ничего не гарантировано. JVM может просто полностью проигнорировать ваш запрос.

Комбинация «вы не знаете, что он сделает», «вы не знаете, поможет ли он вообще» и «вам все равно не нужно вызывать его» — вот почему люди так настойчиво говорят, что обычно Вы не должны называть это. Я думаю, что это случай «если вам нужно спросить, следует ли вам использовать это, вы не должны»

РЕДАКТИРОВАТЬ, чтобы решить несколько проблем из другого потока:

После прочтения темы, на которую вы ссылаетесь, есть еще несколько вещей, которые я хотел бы отметить. Во-первых, кто-то предположил, что вызов gc() может вернуть память системе. Это, конечно, не обязательно верно — сама куча Java растет независимо от выделений Java.

Например, JVM будет хранить память (многие десятки мегабайт) и увеличивать кучу по мере необходимости. Это не обязательно возвращает эту память системе, даже когда вы освобождаете объекты Java; можно совершенно свободно удерживать выделенную память для использования в будущих распределениях Java.

Чтобы показать, что System.gc() может ничего не делать, просмотрите ошибку JDK 6668279 и, в частности, наличие опции -XX:DisableExplicitGC VM:

По умолчанию вызовы System.gc() включены (-XX:-DisableExplicitGC). Используйте -XX:+DisableExplicitGC, чтобы отключить вызовы System.gc(). Обратите внимание, что JVM по-прежнему выполняет сборку мусора, когда это необходимо.

Уже было объяснено, что вызов system.gc() может ничего не дать, и что любой код, который «нуждается» в сборщике мусора для работы, сломан.

Однако прагматическая причина, по которой вызов System.gc() является плохой практикой, заключается в том, что это неэффективно. А в худшем случае — ужасно неэффективно! Позвольте мне объяснить.

Типичный алгоритм GC определяет мусор, обходя все не-мусорные объекты в куче и делая вывод, что любой объект, который не был посещен, должен быть мусором. Исходя из этого, мы можем смоделировать общую работу сборки мусора, состоящую из одной части, пропорциональной количеству живых данных, и другой части, пропорциональной количеству мусора; то есть work = (live * W1 + garbage * W2).

Теперь предположим, что вы делаете следующее в однопоточном приложении.

System.gc(); System.gc();
Первый вызов (по нашим прогнозам) выполнит работу (live * W1 + garbage * W2) и избавится от оставшегося мусора.

Второй вызов выполнит работу (live * W1 + 0 * W2) и ничего не вернет. Другими словами, мы проделали (live * W1) работу и не достигли абсолютно ничего.

Мы можем представить эффективность сборщика как количество работы, необходимое для сбора единицы мусора; т.е. эффективность = (live * W1 + garbage * W2) / garbage. Поэтому, чтобы сделать GC максимально эффективным, нам нужно максимизировать значение мусора, когда мы запускаем GC; т.е. ждать, пока куча не заполнится. (А также сделать кучу как можно больше. Но это отдельная тема).

Если приложение не вмешивается (вызывая System.gc()), GC будет ждать, пока куча не заполнится перед запуском, что приведет к эффективной сборке мусора1. Но если приложение заставляет GC запускаться, есть вероятность, что куча не будет заполнена, и в результате мусор будет собираться неэффективно. И чем чаще приложение заставляет GC, тем более неэффективным становится GC.

Примечание: приведенное выше объяснение не учитывает тот факт, что типичный современный GC разделяет кучу на «пространства», GC может динамически расширять кучу, рабочий набор не-мусорных объектов приложения может меняться и так далее. Тем не менее, один и тот же основной принцип применим ко всем настоящим сборщикам мусора2. Заставлять GC работать неэффективно.

Selenium, java, timezone

Тест запускается в одной токе, сайт находится в другой. Обе эти точки могут произвольно изменяться. Но для корректной работы нужно всегда знать корректное время на сервере с сайтом, т.е на фронтенде.

Предлагаю такое решение:

Calendar c = Calendar.getInstance();
c.setTime(new Date());
System.out.println(«Europe zone: » + TimeZone.getTimeZone(«CET»));
System.out.println(«Local zone: » + TimeZone.getDefault());

int europeOffset = TimeZone.getTimeZone(«CET»).getOffset(System.currentTimeMillis());
int localOffset = TimeZone.getDefault().getOffset(System.currentTimeMillis());

System.out.println(«Europe offset: » + amsOffset);
System.out.println(«Local offset: » + localOffset);
int delta = (europeOffset — localOffset) / 60000;
System.out.println(delta + » min»);

c.add(Calendar.MINUTE, delta);

Date currentDate = c.getTime();
System.out.println(«date today = » + currentDate);

Здесь «СЕТ» — часовой пояс на frontend. Его можно передавать как параметр, а можно и правильно хранить в файле property каждого сервера с которым может работать тест.

P.S. Да, летнее /зимнее время тут учтено!

Selenium, Java, время на Frontend

Проблема:
1. Тест может запускаться из разных часовых поясов — локально, на разных серверах с Jenkins.
2. Тест может проверять разные инстансы фронтенда — Demo, Staging, Production.
Всё это может находиться в разных часовых поясах

Задача: тест должен оперировать/определять время фронтенда с которым он работает.

Calendar c = Calendar.getInstance();
c.setTime(new Date());
System.out.println(«Europe zone: » + TimeZone.getTimeZone(«CET»));
System.out.println(«Local zone: » + TimeZone.getDefault());

int europeOffset = TimeZone.getTimeZone(«CET»).getOffset(System.currentTimeMillis());
int localOffset = TimeZone.getDefault().getOffset(System.currentTimeMillis());

System.out.println(«Europe offset: » + amsOffset);
System.out.println(«Local offset: » + localOffset);
int delta = (europeOffset — localOffset) / 60000;
System.out.println(delta + » min»);

c.add(Calendar.MINUTE, delta);

Date currentDate = c.getTime();
System.out.println(«date today = » + currentDate);

Здесь в коде часовой пояс захардкожен. Правильно брать его из параметров фронденда. Но это уже сами ))).

Selenium и iframe

Хром в панели разработчика находит элемент по xPath, а Selenium не хочет по нему кликать и ругается, что элемент не найден.

Проблема в iframe. Selenium не видит элементы внутри iframe. Надо переключить фокус туда. Ну и не забыть потом вернуться.

driver.switchTo().frame(driver.findElement(By.xpath(«//iframe[@id=’iframeM’]»)));
driver.findElement(By.xpath(«//*[@id=’12345′]»)).click(); driverWrapper.switchTo().defaultContent();

Не успевает отработать Click

Исходные данные: автотест на java selenium. Столкнулся с ситуацией что после клика происходит долгая обработка данных и Selenium падает по таймауту. Перелопатил интернет, перепробовал все ожидания — явные, не явные и все другие включая банальную паузу:

            driver.manage().timeouts().setScriptTimeout(180, TimeUnit.SECONDS);
            driver.manage().timeouts().implicitlyWait(180, TimeUnit.SECONDS);
            driver.manage().timeouts().pageLoadTimeout(180, TimeUnit.SECONDS);

Ничего из этого не помогает. Автотест висит на клике, не переходит к следующей команде, а по истечению времени ожидания — падает.

Решение проблемы пришло с неожиданной для меня стороны и оказалось, как и все гениальное ), простым.

try {
                    driver.findElement(By.xpath("//*[@id='a_do_import']")).click();
                } catch (Exception exception) {
                    logger.info("Exception was catch, is waiting 2 min.");
                    new Pause("120000").act(driver, context, reporter);
                    logger.info("Reload page.");
                    ...
}

Ловим и обрабатываем ошибку сами.

Определяем точное время с учетом часового пояса и летнего/зимнего времени

Ниже пример для средне европейского времени.

Calendar c = Calendar.getInstance();
boolean isSummer = TimeZone.getTimeZone(«ECT»).inDaylightTime(c.getTime());
if (isSummer) {
//Summer time
c.add(Calendar.MINUTE, -60);
} else {
//Winter time
c.add(Calendar.MINUTE, -120);
}

Обратите внимание, здесь не используется устаревший класс Date().

Java жрет память

Что делать, если приложение написанное на Java жрет много оперативки? Может быть это ваш случай:

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

static int a[1024*1024*1024/sizeof(int)];

Java, работа с датой

Форматирование даты.
Преобразование даты в строку по формату.
увеличение даты на дни, недели или часы.


Date dateNow;
dateNow = new Date();
SimpleDateFormat formatDate = new SimpleDateFormat("yyyyMMddHHmmssSSS");
SimpleDateFormat formatDate1 = new SimpleDateFormat("dd MM yyyy");
String newDeviceImei = formatDate.format(dateNow);
String startDate = formatDate1.format(dateNow);
Calendar c = Calendar.getInstance();
c.setTime(dateNow);
c.add(Calendar.DATE, 30);
Date currentDatePlus = c.getTime();
String endDate = formatDate1.format(currentDatePlus);
String deviceModel = "Apple iPhone 8";