В последнее время я работаю над переходом с Java8 на Java17. На ранней стадии я провел некоторые приготовления, но в процессе обновления все еще возникают некоторые проблемы. Некоторая информация записана следующим образом, разделенная на несколько частей. части:
Предки сажали деревья для будущих поколений, чтобы они могли наслаждаться тенью. Если вам нужно обновиться, вы можете обратиться к нему, чтобы не попасть в ловушки. . .
В Java11 Предложение было внесено в JEP 320: Remove the Java EE and CORBA Modules (openjdk.org/jeps/320) Предложение удалено Java EE and CORBA Модули необходимо вводить вручную, если они используются в проекте. Например, в коде используется javax.annotation.*
Следующий пакет:
public abstract class FridayAgent
@PreDestroy
public void destroy() {
agentClient.close();
}
}
Соответствующие классы не будут найдены во время компиляции. Это потому, что Java EE Уже в Java 9
в отмечен deprecated,Java 11 официально удален и может быть введен вручную javax упаковка:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
Например, sun.misc.BASE64Encoder, это просто, достаточно заменить класс инструмента.
[ERROR] symbol: class BASE64Encoder
[ERROR] location: package sun.misc
Младшая версия netty использует sun.misc.*, и сообщение об ошибке компиляции выглядит следующим образом:
Caused by: java.lang.NoClassDefFoundError: Could not initialize class io.netty.util.internal.PlatformDependent0
at io.netty.util.internal.PlatformDependent.getSystemClassLoader(PlatformDependent.java:694) ~[netty-all-4.0.42.Final.jar!/:4.0.42.Final]
Соответствующий исходный код выглядит следующим образом:
/**
* The {@link PlatformDependent} operations which requires access to {@code sun.misc.*}.
*/
final class PlatformDependent0 {
}
https://github.com/netty/netty/issues/6855
Сообщение об ошибке следующее:
Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:compile (default-compile) on project encloud-common: Fatal error compiling: java.lang.ExceptionInInitializerError: Unable to make field private com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors com.sun.tools.javac.processing.JavacProcessingEnvironment.discoveredProcs accessible: module jdk.compiler does not "opens com.sun.tools.javac.processing" to unnamed module
Если вы используете его в своем проекте ломбок, а если это более низкая версия, то появится ломбок Принцип заключается в том, чтобы проделать некоторые трюки во время компиляции, используя com.sun.tools.javac
Проблему можно решить, обновив до последней версии файл, указанный ниже. пс, лично мне это не нравится lombok, При отладке код и class Действительно отвратительно ошибаться.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!-- <version>1.16.4</version>-->
<version>1.18.24</version>
</dependency>
Наш бэкэнд много лет назад был полностью основан на Kotlin, и обновление Kotlin также является нашим главным приоритетом.
[ERROR] Failed to execute goal org.jetbrains.kotlin:kotlin-maven-plugin:1.2.71:compile (compile) on project encloud-core: Compilation failure [ERROR] Unknown JVM target version: 17 [ERROR] Supported versions: 1.6, 1.8
Kotlin начинает поддерживать байт-код Java17 в версии 1.6.0. Компиляция ниже 1.6.0 напрямую сообщит об ошибке.
доступныйjdeps --jdk-internals --multi-release 17 --class-path . encloud-api.jar
Провести анализ зависимостей проекта
картина
Таким образом, вы сможете узнать, какие библиотеки необходимо обновить.
на Яве В этой области существуют известные фреймворки ведения журналов: slf4j, log4j. и т. д., эти платформы предоставляют унифицированный программный интерфейс, позволяющий пользователям добиться персонализированной настройки вывода журнала с помощью простой конфигурации, такой как log тег, уровень (информация, отладка и т. д.), контекст (тема идентификатор, номер строки, время и т. д.), в JVM Внутри компании всегда не хватало таких стандартов, поэтому мы вышли Unified Ведение журнала реализует унификацию форматов журналов. Именно об этом мы и поговорим дальше. Unified Logging
。
С чем мы больше всего контактируем, так это с gc авторизоваться java8 , мы настраиваем gc Параметры журнала: -Xloggc:/tmp/gc.log
。существовать JVM Кроме GC и большое количество других связанных журналов, таких как потоки, ОС Подожди, в новом Unified Logging В журнале метод вывода журнала изменен на java -Xlog:xxx
,GC Оно больше не является чем-то особенным, просто формой существования журнала.
java -Xlog -version
Вывод следующий:
картина
Вы можете видеть, что в выводе журнала есть не только журналы, связанные со сборщиком мусора, но и информация, связанная с потоками операционной системы. Фактически, существует множество частей производителей журналов Java, таких как потоки, загрузка классов, выгрузка, точка сохранения, компакт-диски и т. д.
картина
В конечном итоге печать журналов требует ответа на три вопроса:
Сначала давайте посмотрим, какая часть, как указать, какую информацию выводить. Внутри JVM это называется селекторами.
JVM использует <tag-set>=<level>
выражается в виде селекторы, по умолчанию, теги дляall
,Представляет все теги,level для INFO
,java -Xlog -version
Эквивалент следующей формы
java -Xlog:all=info -version
Если мы хотим вывести тег для gc, уровень журнала для debug Журнал можно использовать java -Xlog:gc=debug
формы:
$ java -Xlog:gc=debug -version
[0.023s][info][gc] Using G1
[0.023s][debug][gc] ConcGCThreads: 3 offset 22
[0.023s][debug][gc] ParallelGCThreads: 10
[0.024s][debug][gc] Initialize mark stack with 4096 chunks, maximum 524288
Это выведет tag для GC, уровень для debug информация журнала.
Однако здесь есть довольно сложный момент: tag Правило соответствия является точным совпадением, если в журнале есть. tag да gc,metaspace
,По вышеуказанному правилу матчи не приезжать,Мы можем вручную указать метод вывода.
$ java -Xlog:gc+metaspace -version
[0.022s][info][gc,metaspace] CDS archive(s) mapped at: ... size 12443648.
[0.022s][info][gc,metaspace] Compressed class space mapped at: reserved size:...
[0.022s][info][gc,metaspace] Narrow klass base:..., Narrow
klass shift: 0, Narrow klass range: 0x100000000
Селектор здесь Также да можно комбинировать, разные selector Просто используйте запятые, чтобы разделить их. Например, вывод одновременно gc
и gc+metaspace
Эти две категории tag Лог можно записать так:
$ java -Xlog:gc=debug,gc+metaspace -version
[0.020s][info][gc] Using G1
[0.020s][debug][gc] ConcGCThreads: 3 offset 22
[0.020s][debug][gc] ParallelGCThreads: 10
[0.020s][debug][gc] Initialize mark stack with 4096 chunks, maximum 524288
[0.022s][info ][gc,metaspace] CDS archive(s) mapped at:
[0.022s][info ][gc,metaspace] Compressed class space mapped at:
[0.022s][info ][gc,metaspace] Narrow klass base: 0x0000000800000000
Конечно, сделать это очень хлопотно, JVM Предусмотрены подстановочные знаки *
Например, чтобы решить проблему точного соответствия, нам нужно, чтобы все tag для gc Лог можно записать так:
$ java -Xlog:gc*=debug -version
[0.024s][debug][gc,heap] Minimum heap 8388608
[0.024s][info ][gc ] Using G1
[0.024s][debug][gc,heap,coops] Heap address: 0x0000000707400000
[0.024s][debug][gc ] ConcGCThreads: 3 offset 22
[0.024s][debug][gc ] ParallelGCThreads: 10
[0.024s][debug][gc ] Initialize mark stack with 4096 chunks
[0.024s][debug][gc,ergo,heap ] Expand the heap. requested expansion amount:
[0.025s][debug][gc,heap,region] Activate regions [0, 125)[0.025s][debug][gc,ihop ] Target occupancy update: old: 0B, new: 262144000B
[0.025s][debug][gc,ergo,refine] Initial Refinement Zones: green: 2560
[0.026s][debug][gc,task ] G1 Service Thread
[0.026s][debug][gc,task ] G1 Service Thread (Periodic GC Task) (register)
[0.026s][info ][gc,init ] Version: 17.0.3+7 (release)
...
если ты только хочешь INFO логи уровня, можно опустить level настройки, используйте java -Xlog:gc* -version
Вот и все.
Если вы хотите знать, какие персонализированные tag Вы можете выбрать, вы можете использовать java -Xlog:help
чтобы найти все доступные tag。
Итоги этапа
картина
Часть 2: Куда выводить (вывод)
По умолчанию журнал выводится на стандартный вывод, а jvm поддерживает следующие три метода вывода:
Вообще говоря, мы будем выводить лог в файл для облегчения дальнейшего анализа.
-Xlog:all=debug:file=/path_to_logs/app.log
Вы также можете указать размер и способ распиловки бревна.
-Xlog:gc*:file=/path_to_logs/app.log:filesize=104857600,filecount=5
Помимо обычной информации, каждый журнал также содержит много контекстной информации, связанной с журналом. jvm серединаодеялосказатьдля decorators
,Доступны следующие варианты.
картина
Например, вы можете использовать java -Xlog:all=debug:stdout:level,tags,time,uptime,pid -version
возможность распечатать журнал.
[2022-06-15T19:54:01.529+0800][0.001s][5235][info ][os,thread] Thread attached
[2022-06-15T19:54:01.529+0800][0.001s][5235][debug][os,thread] Thread 5237 stack...
[2022-06-15T19:54:01.529+0800][0.001s][5235][debug][perf,datacreation]
Формат вывода следующий:
-Xlog:[selectors]:[output]:[decorators][:output-options]
Вот дополнительная точка знаний, значение да по умолчанию:
можно увидеть GC Соответствующие параметры были собраны для Xlog Далее, их было много раньше Java8 Параметры подбыл Удалить или отметитьдля Истекший。
напримерPrintGCDetails
был -Xlog:gc*
заменять:
java -XX:+PrintGCDetails -version
[0.001s][warning][gc] -XX:+PrintGCDetails is deprecated. Will use -Xlog:gc* instead.
Также отмечены параметры, обычно помеченные как устаревшие. -XX:+PrintGC
и -Xloggc:<filepath>
,Параметры до и после миграции следующие:
-Xlog:gc*
Кроме того, большое количество GC параметры удаляются, например часто используемые параметры -XX:+PrintTenuringDistribution
,Java17 Откажется начинать
java -XX:+PrintTenuringDistribution -version
Unrecognized VM option 'PrintTenuringDistribution'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Более подробные параметры удаления следующие:
CMSDumpAtPromotionFailure,
CMSPrintEdenSurvivorChunks,
GlLogLevel,
G1PrintHeapRegions,
G1PrintRegionLivenessInfo,
G1SummarizeConcMark,
G1SummarizeRSetStats,
G1TraceConcRefinement,
G1TraceEagerReclaimHumongousObjects,
G1TraceStringSymbolTableScrubbing,
GCLogFileSize, NumberofGCLogFiles,
PrintAdaptiveSizePolicy,
PrintclassHistogramAfterFullGC,
PrintClassHistogramBeforeFullGC,
PrintCMSInitiationStatistics
PrintCMSStatistics,
PrintFLSCensus,
PrintFLSStatistics,
PrintGCApplicationConcurrentTime
PrintGCApplicationStoppedTime,
PrintGCCause,
PrintGCDateStamps,
PrintGCID,
PrintGCTaskTimeStamps,
PrintGCTimeStamps,
PrintHeapAtGC,
PrintHeapAtGCExtended,
PrintJNIGCStalls,
PrintOldPLAB
PrintParallel0ldGCPhaseTimes,
PrintPLAB,
PrintPromotionFailure,
PrintReferenceGC,
PrintStringDeduplicationStatistics,
PrintTaskqueue,
PrintTenuringDistribution,
PrintTerminationStats,
PrintTLAB,
TraceDynamicGCThreads,
TraceMetadataHumongousAllocation,
UseGCLogFileRotation,
VerifySilently
Большинство этих удаленных параметров можно найти в новой системе журналов, например: PrintHeapAtGC
Этот параметр можно использовать -Xlog:gc+heap=debug
заменить
$ java -Xlog:gc+heap=debug -cp . G1GCDemo01
[0.004s][debug][gc,heap] Minimum heap 8388608 Initial heap 268435456 Maximum heap
hello, g1gc!
[12.263s][debug][gc,heap] GC(0) Heap before GC invocations=0 (full 0):
[12.265s][debug][gc,heap] GC(0) garbage-first heap
[12.265s][debug][gc,heap] GC(0) region size 2048K, 1 young (2048K)
[12.265s][debug][gc,heap] GC(0) Metaspace used 3678K
[12.265s][debug][gc,heap] GC(0) class space used 300K
[12.280s][debug][gc,heap] GC(0) Uncommittable regions after shrink: 124
Хотя это и не интуитивно понятно, вы должны помнить -XX:+PrintGCApplicationStoppedTime
и -XX+PrintGCApplicationConcurrentTime
Эти два параметра вместе -Xlog:safepoint
заменять.
Также есть общий параметр -XX:+PrintAdaptiveSizePolicy
одеяло -Xlog:gc+ergo*=trace
заменять,
[0.122s][debug][gc, ergo, refine] Initial Refinement Zones: green: 23, yellow:
69, red: 115, min yellow size: 46
[0.142s ][debug][gc, ergo, heap ] Expand the heap. requested expansion amount: 268435456B expansion amount: 268435456B
[2.475s][trace][gc, ergo, cset] GC(0) Start choosing CSet. pending cards: 0 predicted base time: 10.00ms remaining time:
190.00ms target pause time: 200.00ms
[2.476s][trace][gc, ergo, cset ] GC(9) Add young regions to CSet. eden: 24 regions, survivors: 0 regions, predicted young
region time: 367.19ms, target pause time: 200.00ms
[2.476s ][debug][gc, ergo, cset ] GC(0) Finish choosing CSet. old: 0 regions, predicted old region time: 0.00ms, time
remaining: 0.00
[2.826s][debug][gc, ergo] GC(0) Running G1 Clear Card Table Task using 1 workers for 1 units of work for 24 regions.
[2.827s][debug][gc, ergo] GC (0) Running G1 Free Collection Set using 1 workers for collection set length 24
[2.828s][trace][gc, ergo, refine] GC(0) Updating Refinement Zones: update rs time: 0.004ms, update rs buffers: 0, update rs
goal time: 19.999ms
[2.829s][debug][gc, ergo, refine] GC(0) Updated Refinement Zones: green: 23, yellow: 69, red: 115
[3.045s][trace][gc, ergo, set ] GC(1) Start choosing CSet. pending cards: 5898 predicted base time: 26.69ms remaining
time: 173.31ms target pause time: 200.00ms
[3.045s][trace][gc, ergo, cset ] GC(1) Add young regions to Set. eden: 9 regions, survivors: 3 regions, predicted young
region time: 457.38ms, target pause time: 200.00ms
[3.045s][debug](gc, ergo, set ] GC(1) Finish choosing CSet. old: @ regions, predicted old region time: 0.00ms, time
remaining: 0.00
[3.090s ][debug][gc, ergo
] GC (1) Running G1 Clear Card Table Task using 1 workers for 1 units of work for 12 regions.
[3.091s][debug][gc, ergo
GC (1) Running G1 Free Collection Set using 1 workers for collection set length 12
[3.093s][trace][gc, ergo, refine] GC(1) Updating Refinement Zones: update rs time: 2.510ms, update rs buffers: 25, update rs
goal time: 19.999ms
[3.093s ][debug][gc, ergo, refine] GC(1) Updated Refinement Zones: green: 25, yellow: 75, red: 125
Глядя на изменения в этой части исходного кода, можно понять, что это действительно так, существует Java8 середина,PSYoungGen::resize_spaces
Код выглядит следующим образом:
картина
на Яве17 , эта часть бревна печатает одеяло gc+ergo Теги журнал замены:
картина
Есть другое поколение GC Очень полезный параметр в -XX:+PrintTenuringDistribution
,сейчассуществоватьодеяло gc+age=trace
заменять
Полная таблица соответствия изменения параметров выглядит следующим образом:
картина
картина
картина
картина
-XX:+PrintGCDetails \ // gc*
-XX:+PrintGCApplicationStoppedTime \ // safepoint
-XX:+PrintGCApplicationConcurrentTime \ // safepoint
-XX:+PrintGCCause \ // По умолчанию будет выведено
-XX:+PrintGCID \ // По умолчанию будет выведено
-XX:+PrintTenuringDistribution \ // gc+age*=trace
-XX:+PrintGCDateStamps \ // :time,tags,level
-XX:+UseGCLogFileRotation \ // :filecount=5,filesize=10M
-XX:NumberOfGCLogFiles=5 \ // :filecount=5,filesize=10M
-XX:GCLogFileSize=10M \ // :filecount=5,filesize=10M
-Xloggc:/var/log/date +%FT%H-%M-%S-gc.log \ // -Xlog::file=/var/log/%t-gc.log
После изменения:
-Xlog:
gc*,
safepoint,
gc+heap=debug,
gc+ergo*=trace,
gc+age*=trace,
:file=/var/log/%t-gc.log
:time,tags,level
:filecount=5,filesize=10M
-Xlog:
// selections
codecache+sweep*=trace,
class+unload, // TraceClassUnloading
class+load, // TraceClassLoading
os+thread,
safepoint, // TraceSafepoint
gc*, // PrintGCDetails
gc+stringdedup=debug, // PrintStringDeduplicationStatistics
gc+ergo*=trace,
gc+age=trace, // PrintTenuringDistribution
gc+phases=trace,
gc+humongous=trace,
jit+compilation=debug
// output
:file=/path_to_logs/app.log
// decorators
:level,tags,time,uptime,pid
// output-options
:filesize=104857600,filecount=5
на Яве8 , никто не может запретить вам доступ к определенным пакетам, таким как sun.misc не имеет ограничений на отражение, если setAccessible(true) Вот и все. Java9 После модуляризации все изменилось. Можно только пройти. --add-exports
и --add-opens
нарушить инкапсуляцию модуля
например:
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.base/java.nio=ALL-UNNAMED
--add-opens java.base/java.security=ALL-UNNAMED
--add-opens java.base/java.text=ALL-UNNAMED
--add-opens java.base/java.time=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/jdk.internal.access=ALL-UNNAMED
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED
CMS официально уходит со сцены истории, G1 Официальное вступление во владение ZGC Готов к работе. в ГК С точки зрения выбора алгоритма, в настоящее время G1 Ну давай же лучший выбор,ZGC потому чтодляиметь Памятьзаниматьодеяло OS Отмечено слишком высоко (три разShared Память)Раздутая проблема, процесс может покрыть OOM-killer Убийство.
Нижний уровень ZGC использует технологию цветных указателей, используя три представления (Marked0, Marked1 и Remapped) для объединения с той же областью области памяти. Принципследующий:
##include <iostream>
##include <sys/mman.h>
##include <sys/stat.h>
##include <fcntl.h>
##include <unistd.h>
##include <cstdio>
##include <cstdlib>
int main() {
// Функция shm_open() используется для открытия или создания общей области Память. Два процесса могут управлять одной и той же общей Памятью, передав одно и то же имя функции shm_open().
int fd = ::shm_open("/test", O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd < 0) {
shm_unlink("/test");
perror("shm open failed");
return 0;
}
size_t size = 1 * 1024 * 1024 * 1024;
// После создания общего Память размер по умолчанию равен 0, поэтому вам необходимо установить размер общего Память. Функцию ftruncate() можно использовать для исправления файла или разделения размера Память.
::ftruncate(fd, size);
int prot = PROT_READ | PROT_WRITE;
// После создания общей Памяти вам необходимо сопоставить общую Память с адресным пространством вызывающего процесса. Это можно сделать с помощью функции mmap().
uint32_t *p1 = (uint32_t *) (mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
uint32_t *p2 = (uint32_t *) (mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
uint32_t *p3 = (uint32_t *) (mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
::close(fd);
*p1 = 0xcafebabe;
::printf("Address of addr1: %p, value is 0x%x\n", p1, *p1);
::printf("Address of addr2: %p, value is 0x%x\n", p2, *p2);
::printf("Address of addr3: %p, value is 0x%x\n", p3, *p3);
::getchar();
*p2 = 0xcafebaba;
::printf("Address of addr1: %p, value is 0x%x\n", p1, *p1);
::printf("Address of addr2: %p, value is 0x%x\n", p2, *p2);
::printf("Address of addr3: %p, value is 0x%x\n", p3, *p3);
::getchar();
munmap(p1, size);
munmap(p2, size);
munmap(p3, size);
shm_unlink("/test");
std::cout << "hello" << std::endl;
}
ты можешь себе представить p1、p2、p3 Эти три района Память да ZGC три вида.
Но дасуществовать Linux В статистике, хотя да делится Память, да все равно засчитается три раза, например RES。
Это же приложение использует G1 RES и показывает, что занимает 2G, а ZGC показывает, что занимает 6G.
java -XX:+AlwaysPreTouch -Xms2G -Xmx2G -XX:+UseZGC MyTest
java -XX:+AlwaysPreTouch -Xms2G -Xmx2G -XX:+UseG1GC MyTest
картина
Далее мы обсудим G1 Соответствующий.
Подробное введение есть в книге «Анализ и настройка исходного кода JVM G1». Есть две основные причины:
Такой как-Xmn, -XX:NewSize, -XX:MaxNewSize, -XX:SurvivorRatio
Даже не будь здесь G1 появляется, вам нужно только контролировать максимальную и минимальную кучу и целевое время паузы.
IHOP Значение по умолчаниюдля 45, это значение да является обязательным условием для запуска одновременной маркировки, только когда общее пространство Память старого поколения 45% Только после этого будет запущена задача параллельной маркировки.
Увеличение этого значения: приводит к тому, что параллельная маркировка потенциально может занять больше времени, вызывая YGC и Mixed-GC Количество разделов во время сбора данных становится меньше и может быть установлено на основе среднего объема памяти, занимаемого приложением в целом.