Screenshot

Лучшие программы для скриншотов. Чем удобнее делать screenshot на win, mac, linux.

Для скриншотов хочу посоветовать великолепный Snipaste, не знаю, как я раньше жил без него.

Если вы пользуетесь Windows 10 или 11, то сочетание клавиш Win+Shift+S дает возможность выделить любой регион на экране и сделать скриншот.

А сочетание Win+V открывает историю буфера обмена откуда этот скриншот можно вытащить. Т.е. сделать сразу несколько снимков экрана последовательно, а потом вставить в одно сообщение в телеграмме без переключения туда-сюда между окнами.
Alt+PrtSc — копирует в буфер только активное окно. Тоже удобно.

На Маке аналог: Cmd+Shift+4
cmd+shift+control+c — делает скриншот в буфер обмена, а не в файл, что еще круче
По cmd+shift+5 можно один раз настроить как удобно — в файл сохранять или в буфер и потом жать cmd+shift+4

SnagIt, очень удобно.

Spectacle, Flameshot, Scrot.

Убунтовый скриншотер -_-
https://help.ubuntu.com/stable/ubuntu-help/screen-shot-record.html
До этого, когда сидел на awesomewm, висел скрот.

Greenshot как вариант.

А лучше установить Flameshot (все 3 системы), поставить на PrintScr и радоваться жизни.
https://flameshot.org/
https://github.com/flameshot-org/flameshot

А если поставить Microsoft Power Toys, то Win + Shift + T дает возможность выделить любой регион на экране, распознать текст в нём, и скопировать этот текст в буфер.

Есть же шотилки типа ShareX, которые всё это ещё в десять раз удобнее делают.
Плюсую к ShareX, очень мощная и настраиваемая штука

На линухе я вот научился запускать сочетанием клавиш maim, которая сохраняет выделенную область экрана в файл, потом копировать этот файл в clipboard:
echo «data:image/png;base64,$(base64 -w0 /tmp/$file.png)» | xclip -selection clipboard -t ‘image/png’
или
xclip -selection clipboard -t ‘image/png’ -i $file.png
или
cat photo_2022-11-13_22-36-52.jpg | xclip -sel clip -t image/png
Вообще на стаковерфлоу много постов с кучей вариантов

xUbuntu. Использую Shutter. Пишет одновременно в файл и буфер. Скрин можно отредактировать. Какую область по какому шоткату брать — настраивается.

Да как вы все вообще живёте-то без Greenshot?

Selenium java code review #1

Code review of Selenium java. Примеры говнокода из реальных проектов и примеры его улучшения. Не обязательно идеальные, но тем не менее лучшие )

Wrong way:

//Wait 15 min till e-Mail waiting time
logger.info("e-Mail sent out, wait 15 min till it will be on patrick@test.com");
Thread.sleep(900000);
logger.info("15 min left go check Mail");

Good way:

//check that e-mail was received
By searchButtonBy = By.xpath("//td/input[@name='searchbutton']");
By subjectBy = By.xpath("//a[contains(text(),'"+ emailSubject +"')]");
int count = driver.findElement(subjectBy).size();
int j = 1;
logger.info("Check e-mail every 10 sec. during 10 min.");
while ((count < 1) && (j < 60)) {
    // check e-mail during 3 min and every 10 sec.
    j++;
    Thread.sleep(10000);
    new driver.findElement(searchButtonBy).click();
    count = driver.findElements(subjectBy).size();
    logger.info(j +". number of emails -  " + count);
}
if (count < 1) throw new Exception("There is no e-mail, something went wrong.");

Установка компонентов temporal.io

Начальная установка компонентов temporal.io на linux ubuntu (xubuntu)

https://t.me/ru_temporal_io

  1. Ставим докер 

Дистрибутив Docker, доступный в официальном репозитории Ubuntu, не всегда является последней версией программы. Лучше установить последнюю версию Docker, загрузив ее из официального репозитория Docker. Для этого добавляем новый источник дистрибутива, вводим ключ GPG из репозитория Docker, чтобы убедиться, действительна ли загруженная версия, а затем устанавливаем дистрибутив. 

Сначала обновляем существующий перечень пакетов: 

sudo apt update 
 

Затем устанавливаем необходимые пакеты, которые позволяют apt использовать пакеты по HTTPS: 

sudo apt install apt-transport-https ca-certificates curl software-properties-common 
 

Затем добавляем в свою систему ключ GPG официального репозитория Docker: 

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 
 

Добавляем репозиторий Docker в список источников пакетов APT: 

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" 
 

Затем обновим базу данных пакетов информацией о пакетах Docker из вновь добавленного репозитория: 

sudo apt update 
 

Следует убедиться, что мы устанавливаем Docker из репозитория Docker, а не из репозитория по умолчанию Ubuntu: 

apt-cache policy docker-ce 

Далее устанавливаем Docker: 

sudo apt install docker-ce 
 

Теперь Docker установлен, демон запущен, и процесс будет запускаться при загрузке системы.  Убедимся, что процесс запущен: 

sudo systemctl status docker 

Чтобы не вводить sudo каждый раз при запуске команды docker, добавьте имя своего пользователя в группу docker и группу sudo: 

sudo usermod -aG docker user 
sudo usermod -aG sudo user 

Для применения этих изменений в составе группы необходимо разлогиниться и снова залогиниться на сервере или задать следующую команду: 

su - ${USER} 
 

Для продолжения работы необходимо ввести пароль пользователя. 

Убедиться, что пользователь добавлен в группу docker можно следующим образом: 

id -nG  

Output:
sammy sudo docker 
 

Если вы хотите добавить произвольного пользователя в группу docker, можно указать конкретное имя пользователя: 

2. Установка Docker Compose 

Мы проверим текущую версию и при необходимости обновим ее с помощью следующей команды: 

sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 
 

После этого мы настроим разрешения: 

sudo chmod +x /usr/local/bin/docker-compose 
 

Затем мы проверим, что установка прошла успешно, с помощью проверки версии: 

docker-compose --version 
 

В результате должна быть выведена установленная нами версия: 

Output:
docker-compose version 1.21.2, build a133471 

 Создаем ссылку  

$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose   

Рестарт сервиса 

$ sudo service docker restart 

3. Клонируем контейнер

Then clone the temporalio/docker-compose repository and run docker-compose up from the root of that repo: 

git clone https://github.com/temporalio/docker-compose.git 
cd docker-compose 
docker-compose up 
 

When the Temporal Cluster is running, the Temporal Web UI becomes available in your browser: localhost:8080 

Открываем браузер и вводим в адресной строке localhost:8080

Temporal.io по русски. Вступительное видео.

https://t.me/temporal_io

Расшифровка вступительного видео по Temporal with Java

0:00
ладно пойдем Дмитрий начнем хорошо ты можешь просто
0:06
перейти к следующему слайду
0:12
так что да, давайте просто начнем с самого начала, мы говорим, что Temporal
0:18
движок рабочего процесса, но что это вообще значит, потому что рабочего процесса много
0:24
двигателей на рынке и как вообще это слово для многих
0:29
людей означает что-то из похожего бизнес-домена, что используется как гм
0:35
люди бизнес-уровня для создания рабочих процессов высокого уровня, обычно в графических редакторах и т. д.
0:42
Temporal очень отличается от большинства подобных решений рабочего процесса, потому что, как мы
0:47
всегда говорим, что Temporal рабочий процесс — это код, поэтому наши основные пользователи и наша основная цель
0:56
инженеры и инженеры приложения гм и это
1:02
как мы сильно отличаемся с точки зрения нашего позиционирования с точки зрения нашего использования
1:07
кейсы из множества других движков рабочего процесса и э-э
1:14
как просто так есть много приложений потенциальных приложений рабочего процесса, но
1:20
в связи с сегодняшней встречей и обсуждением давайте просто сосредоточимся на одном из
1:26
довольно популярная проблема, которая у нас есть в настоящее время в целом в нашем сообществе и в
1:32
наших проектах — это микросервисная архитектура, когда у нас есть микросервисная архитектура
1:39
нам довольно часто приходится вносить последовательные изменения в
1:45
через микросервисы через несколько баз данных через несколько конечных точек и т. д.
1:52
и в основном типичные закономерности и типовые решения проблемы
1:57
сага, основанная либо на оркестровке, либо на хореографии
2:03
так что очень хорошей проблемой для механизма рабочего процесса является
2:08
на самом деле шаблон оркестровки в микросервисах, когда у нас в основном есть
2:14
некий центральный компонент, центральный игрок в системе, выполняющий последовательность действий в
2:21
среда микросервисов и настройка [Музыка]
2:27
этот шаблон и этот подход имеют много проблем, потому что
2:34
все может выйти из строя каждый шаг может выйти из строя внутри
2:39
сети распределенных транзакций или распределенных процессов может выйти из строя
2:46
и сам оркестратор, выполняющий изменения, может выйти из строя
2:52
и мы, как инженеры, в каждом проекте, к которому мы приходим, воспроизводим более или менее одно и то же
3:01
система той же архитектуры для восстановления из ситуаций
3:08
мы создаем реплики и брокеры сообщений
3:13
мы создаем какое-то постоянное состояние, которое позволяет нам восстанавливаться, когда что-то идет
3:20
неправильно мы создаем zookeeper, чтобы иметь возможность масштабироваться и иметь возможность
3:31
распределить работу в кластере, когда мы получим, когда наш проект получит какой-либо
3:37
значительная нагрузка, поэтому в основном все микросервисы
3:43
архитектура и подход более или менее воспроизводят ту же установку, что и
3:49
тот же набор проблем это дорого это запутанно это
3:56
трудно поддерживать для devops, а также чрезвычайно сложно
4:06
с точки зрения наблюдаемости и с точки зрения фактического письма, а не
4:12
просто вызывая конечные точки и выполняя действия, мы должны запланировать события
4:19
мы должны написать весь код, который обрабатывает все виды отказов и
4:26
восстанавливается из всех видов несогласованных состояний и т. д.
4:32
поэтому Temporal в основном обеспечивает решение для всех видов проблем, которые
4:39
может случиться в такой среде, у храма есть
4:45
два компонента Temporal сервер и Temporal SDK, поэтому
4:51
это SDK может быть для разных языков, но все они обеспечивают более или менее одинаковую функциональность
4:58
а Temporal сервер предоставляет возможность хранить состояние рабочего процесса
5:05
как сериализованное представление того, что на самом деле произошло в рабочем процессе
5:11
и мы называем это также историей
5:18
Temporal сервер предоставляет возможность планировать запуск триггеров в будущем
5:25
вы, наверное, знаете все ситуации, когда вдруг ваш проект нуждается в
5:32
что-то вроде э-э, мне нужно выполнить это завтра, и мы начинаем либо приносить все виды
5:39
дополнительные компоненты в систему, такие как планировщики или, что еще хуже, написать наш
5:44
собственный, особенно если нам нужно работать с большим количеством событий
5:50
поэтому Temporal сервер предоставляет возможность планировать запуск триггеров в будущем.
5:59
Temporal SDK предоставляют возможность на самом деле
6:05
сериализовать выполнение вашего кода как историю как последовательность событий
6:12
а также обеспечивает серию абстракций рабочего процесса
6:17
рабочие процессы и действия для фактического масштабирования и выполнения кода, чтобы
6:24
это фреймворк для выполнения кода
6:31
так что я могу перейти к следующему слайду
6:36
давайте просто погрузимся в очень конкретный пример очень конкретного
6:43
очень простой рабочий процесс и как этот рабочий процесс может быть даже
6:49
сериализуется в некоторое последовательное представление
6:54
Итак, здесь у нас есть очень простая функция, которая
7:00
проверяет и обновляет статус учетной записи пользователя и после этого спит в течение 30
7:07
дней, так что в основном здесь мы просто воспроизводим что-то вроде
7:12
каждый месяц нам нужно выполнить какое-то действие над пользователем и после этого ждать следующего месяца
7:20
хм, это можно представить как всего три строки кода, это цикл, это
7:28
действие, которое вам нужно выполнить, и это
7:34
и справа от кода видно, как это может быть представлено на самом деле
7:41
как настойчивая серия действий, давайте просто пройдемся, чтобы дать некоторые
7:49
понять, что происходит, как работает Temporal код и как этот простой код может быть
7:58
в основном сериализуется в состояние в базе данных
8:03
когда вы планируете рабочий процесс вашего клиента
8:09
отправить на сервер команду, которая создает новый рабочий процесс, новую историю для этого рабочего процесса, которая
8:16
в основном выполнение рабочего процесса началось, как вы видите в первой строке, в которой есть все, что
8:23
нужен для запуска рабочего процесса и в основном это входные параметры рабочего процесса
8:30
после того, как Temporal сервер для вас запланирует выполнение этого рабочего процесса
8:38
путем планирования того, что мы называем задачей рабочего процесса, задача рабочего процесса в основном представляет собой сущность
8:45
который представляет собой триггер пользовательского кода, который этот триггер создает, когда
8:52
есть какая-либо причина разблокировать пользовательский код, это либо начало выполнения
8:58
ваш код или его фактический запуск по любой причине, например, из-за
9:06
истечение таймера сна или какой-либо входящий сигнал
9:11
поэтому Temporal сервер создает задачу рабочего процесса и планирует ее
9:17
это то, что происходило в сети номер два после Temporal работника, что на самом деле
9:25
выполняет этот код и размещает этот код гм
9:30
берет событие с сервера, и это момент, когда Temporal
9:38
сервер регистрирует, что выполнение этой задачи рабочего процесса действительно началось
9:44
гм, ваш код на рабочем получает шанс
9:51
чтобы фактически начать выполнение, и он вызывает активность
9:59
так что статус обновления точки действия пользователя здесь в основном является вызовом части
10:05
код, который может выполняться на отдельной машине
10:11
вы хотите вызвать его, и вы хотите сохранить возврат
10:16
ценность этой деятельности — это то, что происходит в истории в следующем фрагменте истории, когда
10:23
сервер храма регистрирует завершение задачи оракула
10:28
почему, поскольку рабочий процесс прямо сейчас заблокирован, запланировано действие и
10:35
ему нужно дождаться своего результата, поэтому, когда код рабочего процесса заблокирован, он
10:40
означает, что это завершение задачи рабочего процесса, и поток выполнения освобождается
10:49
после этого действие фактически запланировано сервером, его подхватывает рабочий
10:55
и рабочий выполняет код в действии, поэтому
11:01
он создает последовательность событий, только что начатых действий, запланированных, начатых, завершенных.
11:08
и когда действие завершено, это означает, что код пользовательского рабочего процесса может продолжить выполнение
11:15
потому что у него есть какой-то триггер, который завершает выполнение действия до
11:21
продолжать продвижение, когда сервер храма планирует запуск нового рабочего процесса при событиях, которые получают
11:28
подхватывается кодом рабочего процесса, который теперь видит, что действие выполнено
11:35
и он переходит в следующую строку, которая ждет 30 секунд в течение 30 дней.
11:42
когда это происходит снова, код рабочего процесса блокируется и
11:48
выполнение освобождается, а задача рабочего процесса получает
11:55
завершено, и давайте отправим отчет на сервер, чтобы получить
12:01
с этим завершением мы также говорим серверу, что нам нужен таймер на 30 дней
12:10
и это то, что записывается в последней строке истории, так что
12:15
история фактически фиксирует факт наличия таймера в этом рабочем процессе
12:21
это должно быть запущено через 720 часов, и Temporal сервер позаботится об этом
12:30
через месяц, когда это произойдет, почему это представляет это представление
12:38
так могущественен и так велик всякий раз, когда мы терпим неудачу на любом этапе этого
12:45
мы можем восстановить состояние нашего рабочего процесса
12:51
путем повторного выполнения этого кода и подачи этой истории событий
12:57
чтобы фактически восстановить рабочий процесс в том состоянии, в котором мы его оставили
13:04
где это не удалось, например, если в следующем месяце кто-то перезагрузит
13:10
сервер, который, скорее всего, будет работать, когда таймер тикает и
13:18
запускает выполнение Temporal SDK, на самом деле сможет
13:24
забрать историю с сервера и восстановить код в том состоянии, в котором мы
13:32
осталось, это одна из основных функций SDKs в Temporal, так что это
13:41
в основном обеспечивает уровень соединения между
13:46
пользовательский код и эти сохраненные события истории и
13:53
таймеры на стороне сервера есть вопросы по этому экрану
13:59
потому что происходит много всего, да, у меня есть вопрос
14:04
так это на самом деле рабочий фрагмент кода слева
14:12
у него было это, я имею в виду, чтобы вывести вывод справа, мне пришлось написать его и запустить
14:18
это так э-э, так Temporal каким-то образом сохранило
14:24
снимок состояния функции да восстанавливать или нет как как код
14:30
продолжится в месяце с кодовой строки
14:36
пять, я не знаю, да, в следующем цикле, как это произойдет
14:41
Итак, давайте представим, что кто-то отключил наш сервер посередине
14:47
нет способа сохранить состояние процесса
14:53
это не разумный способ, который мы можем использовать в производстве, так что
14:59
это сериализованное представление используется для того, что мы называем повторным воспроизведением.
15:06
поэтому мы знаем, что есть рабочий процесс, который сохраняется в базе данных.
15:12
а Temporal сервер через месяц, когда тикает таймер, фактически запланирует новый рабочий процесс
15:20
задача для выполнения на воркере и когда этот воркер получит задачу
15:26
чтобы выполнить его, вы обнаружите, что нет рабочего процесса
15:31
как будто мне нужно восстановиться, и то, что он делает, приносит все
15:37
история с сервера, он берет код, и он в основном соответствует истории для
15:44
код, например, здесь, что произойдет в первой строке в основном
15:50
вызывает действие прямо, когда вместо фактического вызова и
15:55
активность Temporal SDK мы посмотрим на историю и увидим, что эта активность была
16:00
уже выполнено, поэтому мне не нужно повторять шаг и
16:06
он просто будет использовать возвращаемое значение, записанное в истории
16:12
поэтому история сохраняет результаты каждой операции, такой как активность
16:20
выполнение, поэтому использование кода истории будет буквально воспроизводиться до состояния
16:29
там, где мы его оставили, и после этого он продолжит выполнение
16:34
это имеет смысл, потому что это немного сложно
16:39
концепция, и хм, важно понимать, что Temporal не имеет волшебства
16:46
возможность просто сохранить состояние рабочего процесса в настоящее время, которое в настоящее время
16:52
существует в памяти, когда ему нужно восстановить состояние, он должен снова выполнить код
17:00
на основе и использовать историю, которая была сохранена, чтобы восстановить состояние
17:13
ладно ладно так а
17:19
хорошо, спасибо, да, так что это просто важно
17:24
понять, что Temporal SDK существует, чтобы в основном обеспечить именно эту возможность
17:30
когда вы вызываете действие, это вызов действия, которого нет
17:36
просто вызов вашего кода, этот вызов фактически перехватывается
17:41
SDK и активность были запланированы на работника, но
17:47
это не обязательно, если оно уже было выполнено, если оно уже было выполнено в
17:53
в этом случае SDK знает, что он не должен быть редким и
17:58
вместо этого будет использоваться постоянное состояние, поэтому Temporal SDK предоставляет эти способы для
18:08
в основном перехватывать контроль над кодом, чтобы обеспечить гарантии того, что мы
18:15
пытаясь обеспечить
18:21
о, спасибо, я думаю, что дальнейшие примеры также будут полезны для меня, так что спасибо
18:27
за ваши ответы, да, конечно, вы хотите бежать, используйте их, подумайте об этом, как
18:34
Дмитрий объяснил, как это делается, но когда вы пишете свои рабочие процессы, вас это не должно волновать, это хорошо понимать
18:40
но когда вы пишете свой рабочий процесс, вы можете просто вызвать сон рабочего процесса на 30 дней, и он просто работает, вы можете думать о том, чтобы относиться к нему как к волшебству, вы можете понять волшебство, но
18:47
когда вы пишете рабочий процесс, вам все равно, это просто то, как вы думаете о своем коде, не может
18:54
поскольку он не привязан к конкретной машине, его всегда можно восстановить, это своего рода виртуальное право, как будто это не так.
18:59
связанный с определенными блоками, что угодно может выйти из строя, ваш код остается самой важной причиной, почему это очень
19:07
хорошо понимать, что эта лежащая в основе абстракция истории
19:12
потому что код рабочего процесса имеет набор ограничений, что мы обычно говорим, что рабочий процесс
19:19
код должен быть детерминированным, что обычно означает, что должно быть
19:24
отсутствие генерации случайных значений прямо в коде рабочего процесса, кроме использования
19:33
генераторы, которые предоставляет Temporal SDK, или не должно быть модификации
19:40
код рабочего процесса для уже запущенных рабочих процессов без учета детерминизма
19:47
хотели бы понять эту концепцию и ограничения, которые мы накладываем на рабочий процесс
19:52
код, очень полезно понять, как он сериализуется
19:57
потому что если нет понимания механика стерилизации
20:03
вероятно, эти ограничения будут выглядеть искусственными, но у Temporal SDK есть ограничения на
20:11
код рабочего процесса, и это основная причина, потому что он должен быть
20:19
воспроизводимым мы будем, мы должны быть в состоянии использовать записанную историю, чтобы восстановить
20:24
государство тифа ты хочешь
20:29
пойдите с примером, конечно, у меня есть, может быть, еще один два слайда
20:35
только самые простые, а затем перейдите в демоверсию, и мы можем обсудить все это вместе, если вы не против
20:45
эм ладно эм да ну так что спасибо это было круто я имею в виду
20:51
divitry действительно может объяснить это таким образом, что это просто потрясающе, у меня есть только пара
20:58
небольшие слайды номер один, я просто хотел поговорить о самом java SDK
21:04
точно так же, как другие SDK, которые предоставляют Temporal, они очень ненавязчивы, что означает, что вы знаете конкретно
21:10
мы говорим о java, вы действительно можете использовать его в любой среде, это просто библиотека, которую вы
21:17
включите, и вы можете начать использовать его, независимо от того, что у вас есть, если вы создаете новый
21:23
приложения или если у вас есть что-нибудь существующее, например, приложения, которые вы хотели добавить
21:29
рабочие процессы и Temporal процессы на основе модели программирования
21:34
Конечно, это ты знаешь
21:40
можно повторно использовать существующую среду разработки, чтобы вы могли продолжать использовать свои идеи
21:45
хотя, конечно, мы говорим, что темп — это решение рабочего процесса, обычно вы знаете, что люди думают, что
21:51
вы должны принять какие-то пользовательские решения и пользовательские среды и бла-бла-бла с важным, что не
21:57
случае, вы все еще можете использовать свои идентификаторы, которые вы все еще можете развернуть, вы знаете, kubernetes docker или что-то еще
22:04
платформа, которую вы используете в настоящее время или думаете о запуске в будущем
22:09
и то же самое с тестированием и отладкой, вы можете, конечно
22:15
как мы увидим с нашим SDK, вы используете junit четыре и пять, вы можете издеваться над
22:20
вы знаете действия и подобные вещи, и и и действительно пишете свой тест, как и рабочие процессы тестирования
22:28
наряду с вашими тестами, которые у вас уже могут быть в настоящее время тестировать другую часть ваших систем
22:33
а также просто для того, чтобы вы знали, начните, и если вы хотите сделать скриншот этого и
22:40
конечно, вы будете на ютубе позже, вы знаете, одна из вещей, о которых я хотел поговорить, это как
22:46
вы начинаете, конечно, у нас есть наша Temporal документация, специально для java SDK, у нас есть
22:53
репозиторий примеров github, который включает в себя массу различных образцов и
22:58
я думаю, что он растет, список образцов становится больше, и мы действительно прислушиваемся к нашему сообществу, насколько это возможно.
23:05
вопросы, которые у них есть, и и и пытаются предоставить полезные образцы, они выбегают из коробки.
23:12
для вас, чтобы получить представление обо всех различных функциях, которые предоставляет Temporal java SDK
23:19
у нас также есть семинары, у нас было два до сих пор, и один в начале следующей недели, и вот URL и
23:27
и на этих семинарах мы как бы углубляемся в конкретные случаи
23:32
так что, если у вас есть какие-либо вопросы, которые вы знаете, подумайте, хотите ли вы узнать о чем-то еще
23:38
продвинутые концепции Temporal хранения в Java SDK, к которым вы обязательно присоединитесь
23:43
там и задавайте любые вопросы, и, конечно же, у нас есть тонна видео на YouTube, и мы добавляем их
23:49
мы создаем все больше и больше контента, наш ютуб растет так сильно, я
23:54
уверен, вы найдете ряд видео, которые помогут вам начать работу
23:59
гм, так что, насколько хорошо, мы говорили о том, что, как вы знаете, делает SDK и как работает Temporal
24:06
и история, но как бы возвращаясь назад, как вы на самом деле начинаете использовать java SDK в моем проекте?
24:12
вы знаете, что это зависит от вашей системы сборки для gradle, вы просто добавляете пару зависимостей, ну большинство
24:19
важным является Temporal SDK, и здесь у нас есть версия 181, которая является
24:24
последнее и, может быть, Дмитрий может рассказать о том, когда он выпустит, вы знаете, одну девятку и тому подобное, и что за
24:32
временная шкала выглядит как в настоящее время, но да, Temporal зависимость dash SDK действительно похожа на
24:38
основная зависимость SDK включает в себя все API для написания вашего клиента
24:43
код, который вызывает рабочие процессы, чтобы фактически написать ваш рабочий процесс
24:49
код и использование всех видов конструкций, которые вам нужно использовать для
24:54
напиши свой рабочий процесс оркестровки и Дмитрий также коснулся этого хм
25:00
и вы знаете такие вещи, это также гм
25:05
включает в себя много других вещей, вроде более продвинутых, но мы поговорим об этом позже, и, конечно же, вам нужно
25:11
Зависимость от тестирования Зависимость от тестирования позволяет вам иметь полный
25:17
среда тестирования, которая находится в памяти, поэтому вам не нужно иметь
25:22
запуск Temporal сервера, работающего для фактического запуска ваших тестов
25:30
тестирование SDK заключается в том, что у него есть что-то вроде расширенной функции времени, так что даже
25:35
если бы вы, например, как Дмитрий, показали вес своего рабочего процесса за 30 дней, э-э, ваше
25:40
тест может выполняться за миллисекунды, поэтому вы действительно можете использовать рабочий процесс, который мы показали на предыдущем слайде, и и
25:49
протестируйте его, может быть, год или два или любой другой период времени, который вы хотите, и вы, конечно, не можете проверить его в течение
25:55
миллисекунда, и вот, да, крутая проблема, я просто хочу, чтобы вопрос, который у нас есть, был полностью
26:04
полноразмерный сервер, такой как Temporal сервер, для которого требуется база данных и т. д., поэтому
26:10
относительно сложный для операций, у нас есть упрощенная настройка для
26:17
разработка с использованием только docker compose, с помощью которой очень легко запустить настоящий сервер
26:23
но также у нас есть тестовый сервер, чрезвычайно легкий в реализации памяти, который можно использовать для
26:31
модульные тесты, и он ведет себя очень близко к Temporal серверам производства
26:37
поэтому всякий раз, когда мы видим разницу, мы на самом деле исправляем ее, мы сохраняем ее синхронизированной с реальными вещами, поэтому
26:45
чрезвычайно легко использовать полную реализацию, полную реальную реализацию и Temporalнную реализацию в ваших модульных тестах.
26:53
круто, да, и просто чтобы показать вам то же самое для maven, если вы используете maven в качестве сборки
27:00
системе нужно всего две зависимости для настройки, и это то, что вы и так знаете
27:06
очень легко начать работу со стороны SDK в новом или
27:12
с существующими приложениями все в порядке, поэтому я постараюсь сделать очень быструю демонстрацию сейчас и
27:19
это очень похоже на то, что Дмитрий
27:26
о чем мы говорили на своем слайде, это немного отличается, как вы знаете
27:32
не синхронизировался полностью на этом, и это не имеет большого значения, но
27:37
вы знаете, что это делает, у нас есть очень простой метод рабочего процесса, который очень похож на тот же, что и на
27:43
слайд в основном в нашем рабочем процессе в этом случае вместо использования одной учетной записи или
27:50
или идентификатор пользователя, и я буду обновлять его каждые 30 дней в нашем тесте, у нас есть номер учетной записи
27:58
идентификаторы, которые мы получаем, вы знаете, либо от конечных пользователей, либо в ваших приложениях kcp, кто-то может
28:05
войти в какой-то веб-интерфейс и и использовать его в качестве входных данных для вашего э-э
28:11
рабочий процесс как данные, и что мы делаем, мы в основном
28:16
цикл по каждому из наших идентификаторов учетной записи, и для каждого из наших идентификаторов учетной записи мы
28:21
хотите уведомить его о некоторой информации, и это всего лишь небольшая демонстрация
28:26
но только на предыдущем слайде мы показали, что мы вызываем нашу активность
28:32
наша деятельность дмитрий хм объяснил, можно рассматривать как удаленный вызов процедуры, так что это
28:38
будет обрабатываться его планирование, и это будет обрабатываться Temporal сервером, а это
28:44
деятельность снова может быть, как сказал дмитрий, выполнена на совершенно другом
28:50
работник или вы знаете другую службу, в которой они могут размещать эту деятельность, и имеет
28:55
рабочий, который зарегистрировал его, и после того, как это действие завершится, мы просто ради этой демонстрации
29:02
поспите две секунды, и вы поймете, почему это
29:08
гм, у нас также есть, конечно, мы используем Temporal SDK в нашем работнике, поэтому оба
29:16
рабочий процесс, и наш рабочий, и, как вы видели, наш тип стартера, который мы называем
29:21
стартеры или клиентское приложение, где мы хотим вызвать выполнение нашего рабочего процесса, все эти вещи используют Temporal
java SDK, так что вы ничего не знаете, что вам нужно получить дополнительно, чтобы написать работника, вам не нужно ничего получать
29:34
дополнительно, чтобы написать какой-то API для вызова ваших рабочих процессов, весь вид grpc под капотом, э-э
29:42
связь между вашим кодом и Temporal сервером
29:47
обрабатывается нашей Temporal Java
37:09
клиенты учитывают гм правильно и это
37:14
это слово все в порядке, так что это похоже на то, что у меня было, как на этом последнем слайде, который я
37:20
хотел показать, что мы приветствуем всех в сообществе
37:25
пожалуйста, вы знаете, что нам нужен ваш вклад, мы хотели бы получить ваш вклад, мы любим получать гм
37:32
твои твои мысли как ты используешь Temporal как ты используешь java SDK какие у тебя проблемы
37:37
сталкиваться, и лучший способ принять участие, конечно, на github и
37:43
вот URL-адрес нашего репозитория java SDK github
37:48
у нас есть форум, важное сообщество, которым я обязан, и я настоятельно рекомендую вам, если у вас есть какие-либо
37:54
вопросы, которые вы знаете, вопросы для начинающих, чтобы действительно понять наши вопросы, мы всегда готовы ответить и помочь вам
38:00
там, ну, и, конечно, наш Temporal запас — это запас, и мы специально для java у нас есть э-э
38:08
SDK есть java-канал, к которому вы можете присоединиться, и, и вы знаете, участвуйте в сообществе, чтобы вы знали и видели
38:14
а также не только задавать вопросы, но и читать о других людях и о том, как они используют Temporal файлы в java SDK.
38:22
[Музыка]

Сборка мусора Java

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

Переработка памяти включает в себя «циклы» сборки мусора, которые влияют на производительность. Степень воздействия зависит от характера вашего приложения и выбранного вами GC. Хорошая новость заключается в том, что существует более одного сборщика мусора, и каждый последний выпуск Java предлагает больше вариантов. Вы можете выбрать GC, который наилучшим образом соответствует потребностям вашего приложения.

Новые сборщики мусора

В последних двух выпусках Java представлены три новых GC. Мы рассмотрим каждый из них и то, что они добавляют в экосистему.

Java 11 представила Epsilon и сборщик мусора Z (ZGC). Epsilon — это сборщик мусора без операций. Он выделяет новую память, но никогда не перерабатывает ее. ZGC обещает управлять большими объемами памяти с высокой пропускной способностью и коротким временем паузы.

Java 12 добавляет сборщик мусора Shenandoah. Как и ZGC, он управляет большими кучами с коротким временем паузы, но использует совершенно другой подход.

Сборщик мусора Эпсилон

Что такое Эпсилон?

Epsilon — это пассивный или «нерабочий» GC. Он обрабатывает выделение памяти, но не перерабатывает ее, когда объекты больше не используются. Когда ваше приложение исчерпывает кучу Java, JVM отключается. Другими словами, Epsilon позволит вашему приложению исчерпать память и сломаться.

Как использовать Эпсилон 

Параметры командной строкиПримечания
 -XX:+UnlockExperimentalVMOptions Разблокируйте экспериментальные возможности Java.
 -XX:+UseEpsilonGC Используйте Эпсилон ГХ
 -XmxXg Установить размер кучи. JVM завершит работу с OutOfMemoryError, если это количество будет превышено.
 -XX:HeapDumpOnOutOfMemoryError Создайте дамп кучи, если JVM не хватает памяти.
 -XX:OnOutOfMemoryError= Выполнить указанную команду при возникновении ошибки нехватки памяти.


Зачем использовать No-Op GC? 

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

Epsilon устраняет влияние GC на производительность. Нет циклов GC или барьеров чтения или записи. При использовании Epsilon GC ваш код выполняется изолированно. Вы можете использовать его, чтобы увидеть, как сбор мусора влияет на производительность вашего приложения и каков ваш порог памяти, поскольку он сообщит вам, когда он закончится. Если вы думаете, что вам нужно всего четыре гигабайта памяти, запустите его  -Xmx4g и посмотрите, правы ли вы. Если вы ошибаетесь, перезапустите его с  XX:HeapDumpOnOutOfMemoryError включенным и посмотрите на дамп кучи, чтобы увидеть, где вы ошибаетесь.

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

Сборщик мусора Z

Что такое сборщик мусора Z?

ZGC — сборщик мусора с малой задержкой, предназначенный для работы с огромными объемами памяти. Документация Oracle ссылается на многотерабайтные кучи в своем описании Z. Oracle представила ZGC в Java 11. В Java 12 Oracle добавила исправления производительности и выгрузку классов, хотя Z все еще находится в экспериментальном состоянии. Он доступен только в 64-разрядной версии Linux.

Как работает ЗГК?

ZGC работает параллельно с вашим приложением, выполняя всю свою работу в своих потоках. Он использует барьеры нагрузки для ссылок на кучу. Барьеры нагрузки вызывают меньше задержек, чем те, которые накладываются барьерами до и после записи коллектора G1.

ZGC использует преимущества 64-битных указателей с помощью метода, называемого раскрашиванием указателей. Цветные указатели хранят дополнительную информацию об объектах в куче. (Это одна из причин, по которой он ограничен 64-битной JVM.) Ограничив GC кучами размером 4 ТБ, разработчики получили 22 дополнительных бита в каждом указателе для кодирования дополнительной информации. В настоящее время Z использует четыре дополнительных бита. Каждый указатель имеет бит для финализации, переназначения, метки0 или метки1.

Сборщик мусора Z переназначает объекты, когда память становится фрагментированной. Сопоставление позволяет избежать снижения производительности, когда сборщику мусора требуется найти место для нового выделения. Цвет указателя помогает при переназначении, поскольку переназначенная ссылка обнаруживает новое местоположение при следующем доступе.

Когда ваше приложение загружает ссылку из кучи, ZGC проверяет лишние биты. Если ему нужно выполнить какую-либо дополнительную работу (например, получить переназначенный экземпляр), он обрабатывает ее в барьере нагрузки. Это нужно сделать только один раз, когда он загружает ссылку. Это отличает его от барьеров записи, используемых основными сборщиками мусора, такими как G1.

Сборщик мусора Z выполняет свои циклы в своих потоках. Он приостанавливает приложение в среднем на 1 мс. Сборщики G1 и Parallel в среднем составляют около 200 мс.

Как использовать ЗГК

Параметры командной строкиПримечания
 -XX:+UnlockExperimentalVMOptions Разблокируйте экспериментальные возможности Java
 -XX:+UseZGC Используйте ЗГК.
 -XmxXg Установить размер кучи.
 -XX:ConcGCThreads=X Установить количество потоков GC

ZGC — это параллельный сборщик мусора, поэтому установка правильного размера кучи очень важна. Куча должна быть достаточно большой для размещения вашего приложения, но также нуждается в дополнительном запасе, чтобы Z мог удовлетворять новые запросы при перемещении активных объектов. Объем необходимого запаса зависит от того, насколько быстро ваше приложение запрашивает новую память.

ZGC сам попытается установить количество потоков, и обычно это правильно. Но если у ZGC слишком много потоков, ваше приложение будет голодать. Если его недостаточно, вы создадите мусор быстрее, чем сборщик мусора сможет его собрать.

Зачем использовать ZGC?

Дизайн ZGC хорошо работает с приложениями большого размера кучи. Он управляет этими кучами с временем паузы менее 10 мс и незначительно влияет на пропускную способность. Эти времена лучше, чем у G1.

ZGC выполняет маркировку в три этапа. Первая — это короткая фаза остановки мира. Он проверяет корни GC, локальные переменные, которые указывают на остальную часть кучи. Общее количество этих корней обычно минимально и не масштабируется с размером нагрузки, поэтому паузы ZGC очень короткие и не увеличиваются по мере роста вашей кучи.

После завершения начальной фазы ZGC переходит к параллельной фазе. Он проходит по графу объектов и исследует цветные указатели, отмечая доступные объекты. Барьер нагрузки предотвращает конкуренцию между фазой сборки мусора и активностью любого приложения.

После того, как ZGC завершил маркировку, он перемещает живые объекты, чтобы освободить большие разделы кучи для более быстрого выделения памяти. Когда начинается фаза перемещения, ZGC делит кучу на страницы и работает с одной страницей за раз. Как только ZGC завершает перемещение всех корней, остальная часть перемещения происходит в параллельной фазе.

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

Шенандоа

Что такое Шенандоа?

Shenandoah — еще один сборщик мусора с коротким временем паузы. Эти времена короткие и предсказуемые, независимо от размера кучи. Shenandoah был разработан в Red Hat и существует уже несколько лет. Теперь это часть выпуска Java 12.

Как и ZGC, Shenandoah выполняет большую часть своей работы параллельно с работающим приложением. Но его подход к сбору мусора отличается. Shenandoah использует области памяти для управления тем, какие объекты больше не используются, а какие активны и готовы к сжатию. Shenandoah также добавляет указатель переадресации к каждому объекту кучи и использует его для управления доступом к объекту.

Как работает Шенандоа?

Дизайн Shenandoah обменивает параллельные циклы ЦП и пространство на улучшение времени паузы. Указатель переадресации упрощает перемещение объектов, но агрессивные перемещения означают, что Shenandoah использует больше памяти и требует больше параллельной работы, чем другие сборщики мусора. Но он выполняет дополнительную работу с очень короткими паузами в стиле «останови мир».

Фазы Шенандоа

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

Первая фаза содержит первую остановку мира в цикле. Он подготавливает кучу для одновременной маркировки и сканирует корневой набор. Как и в ZGC, длина этой паузы соответствует размеру корневого набора, а не кучи. Затем на параллельной фазе выполняется обход кучи и идентификация доступных и недоступных объектов.

Третий завершает процесс маркировки, сливая ожидающие обновления кучи и повторно сканируя корневой набор. Эта фаза запускает вторую паузу в цикле «останови мир». Количество ожидающих обновлений и размер корневого набора определяют продолжительность паузы.

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

Следующая фаза запускает третью (и самую короткую) паузу в цикле. Это гарантирует, что все потоки GC завершили эвакуацию. По завершении параллельная фаза проходит по куче и обновляет ссылки на объекты, перемещенные ранее в цикле.

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

Как использовать Шенандоа

Параметры командной строкиПримечания
 -XX:+UnlockExperimentalVMOptions Разблокируйте экспериментальные возможности Java.
 -XX:+UseShenanodoahC Используйте Шенандоа GC.
 -XmxXg Установить размер кучи.
 -XX:ShenandoahGCHeuristics=  Выберите эвристику.

Эвристика Шенандоа

Вы можете настроить Shenandoah с одной из трех эвристик. Они определяют, когда GC начинает свои циклы и как он выбирает регионы для эвакуации.

1. Адаптивный : наблюдает за циклами GC и запускает следующий цикл, чтобы он завершился до того, как приложение исчерпает кучу. Эта эвристика является режимом по умолчанию.

2. Статический . Запускает цикл сборки мусора в зависимости от занятости кучи и давления на выделение.

3. Компактный : Непрерывно запускает циклы ГХ. Shenandoah начинает новый цикл, как только заканчивается предыдущий или на основе объема кучи, выделенной с момента последнего цикла. Эта эвристика влечет за собой накладные расходы на пропускную способность, но обеспечивает наилучшее высвобождение пространства.

Режимы отказа

Shenandoah должен собирать кучу быстрее, чем приложение, которое он обслуживает, выделяет его. Если давление выделения слишком велико и для новых выделений недостаточно места, произойдет сбой. У Shenandoah есть настраиваемые механизмы для этой ситуации.

  • Шаг : если Shenandoah начинает отставать от скорости выделения, потоки выделения останавливаются, чтобы наверстать упущенное. Прилавков обычно достаточно для умеренных всплесков распределения. Shenandoah вводит задержки в 10 мс или меньше. Если стимуляция не удалась, Шенандоа перейдет к следующему этапу: вырожденному GC.
  • Вырожденный GC : если происходит сбой распределения, Shenandoah запускает фазу остановки мира. Он использует фазу для завершения текущего цикла GC. Поскольку остановивший мир не соперничает с заявкой на ресурсы, цикл должен завершиться быстро и устранить дефицит распределения. Часто вырожденный цикл происходит после того, как большая часть работы цикла уже завершена, поэтому остановка мира непродолжительна. Однако журнал GC сообщит об этом как о полной паузе.
  • Полный GC : если и стимуляция, и вырожденный GC терпят неудачу, Шенандоа возвращается к полному циклу GC. Этот окончательный сборщик мусора гарантирует, что приложение не завершится с ошибкой нехватки памяти, если не останется кучи.

Зачем использовать Шенандоа?

Shenandoah предлагает те же преимущества, что и ZGC, с большими кучами, но с более широкими возможностями настройки. В зависимости от характера вашего приложения могут подойти различные эвристики. Время паузы может быть не таким коротким, как у ZGC, но оно более предсказуемо.

Хотя Shenandoah не был доступен как часть Java до версии 12, он существует дольше, чем ZGC. Он прошел больше тестов и даже доступен в качестве резервной копии для Java 8 и 10.

Заключение

Сборщик мусора Java прошел долгий путь за несколько коротких лет. Сборщик по умолчанию G1 претерпел значительные улучшения по сравнению с Java 7, и на платформу были добавлены три новых.

В зависимости от ваших потребностей, один из этих новых GC может быть тем, что вам нужно, чтобы вывести производительность вашего Java-приложения на новый уровень.

Низкая производительность или высокие накладные расходы из-за вызовов 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 работать неэффективно.

xubuntu lightdm error

Random logout (Xorg crashing?)
Падает Xorg
Внезапный рестарт сессии xubunta
Рестарт иксов
Падают иксы
Крах(рестарт) Xfce

Смотрим логи

>journalctl -S «2022-03-05 12:10» -U «2022-03-05 22:00»

И видим красные строки

lightdm[19715]: PAM unable to dlopen(pam_kwallet.so): /lib/security/pam_kwallet.so: cannot open shared object file: No such file or directory
lightdm[19715]: PAM adding faulty module: pam_kwallet.so
lightdm[19715]: PAM unable to dlopen(pam_kwallet5.so): /lib/security/pam_kwallet5.so: cannot open shared object file: No such file or directory
lightdm[19715]: PAM adding faulty module: pam_kwallet5.so

Поскольку эта штука глючная и бороться с ней дело неблагодарное, то отключаем ее и живем счастливо.

  1. Редактируем два файла /etc/pam.d/lightdm и /etc/pam.d/lightdm-greeter 
    Коментируем # или вообще удаляем строки
    auth    optional        pam_kwallet.so
    auth    optional        pam_kwallet5.so
    session optional        pam_kwallet.so auto_start
    session optional        pam_kwallet5.so auto_start
    2. Перезапускаем  systemctl restart lightdm

Linux, sqlplus, нет такого файла или каталога

После установки не запускается sqlplus /nolog
Ошибка: sqlplus: command not found

  1. Проверяем наличие переменных окружения
    ORACLE_HOME
    LD_LIBRARY_PATH
    PATH
    Что в них писать, вроде, не проблема — куча статей и документации. Например:
ORACLE_HOME=/opt/oracle/19.2/client
PATH=$ORACLE_HOME/bin:$PATH
LD_LIBRARY_PATH=$ORACLE_HOME:$ORACLE_HOME/lib:$LD_LIBRARY_PATH
export ORACLE_HOME
export LD_LIBRARY_PATH
export PATH
  1. Следующая возможная ошибка

sqlplus: error while loading shared libraries: libsqlplus.so: cannot open shared object file: No such file or directory

Устанавливаем нужную библиотеку. А вот тут практически все статьи умалчивают одну маленькую деталь. Нужная библиотека — libsqlplus.so или libaio или libaio1. Пример установки:

sudo apt-get install libaio1

И нигде не уточняют, что это 64 бита. Но если вы установили 32-битный клиент, то вам это не поможет. А поможет

sudo apt-get install libaio1:i386

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. Да, летнее /зимнее время тут учтено!