Привет, это продолжение статьи, в которой я разбирал разные неочевидные вещи из мира производительности. В этот раз будем копать ещё глубже, хоть и начнём с относительно простых примеров. И да, в этой статье будет много интересного про строки. Да, несмотря на "Катехизис java.lang.String", "The Lord of the Strings: Two Scours" и пары моих статей (раз, два, три) там всё ещё есть куда копать :)

Очевидное — невероятное

Некоторые улучшения кода настолько просты и очевидно полезны, что возможный вред от них не укладывается в голове. Возьмём простой до неприличия код и посмотрим на него в "Идее":

<T> List<T> toList(Set<T> set) {
  var list = new ArrayList<T>();
  for (T item : set) {
    list.add(item);
  }
  return list;
}

Редактор тут же подсветит list.add(item) и подскажет, что "Iteration can be replaced with bulk 'Collection.addAll()' call". Выполнив преобразование, можно ужать тело метода:

var list = new ArrayList<T>();
list.addAll(set);
return list;

"Идея" не унимается и говорит, что "'addAll()' can be replaced with parametrized constructor call", ещё больше сокращая (и ускоряя) тело метода:

return new ArrayList<>(set);

Эти преобразования настолько очевидны и полезны для большинства наиболее употребимых коллекций, что здесь я не буду это доказывать бенчмарками. Для каких-то коллекций, впрочем, выигрыш не столь велик, например для ArrayDeque, и виной всему некоторые её особенности:

  • запрет вставки null;

  • внутренний массив выделяется с запасом.

Из-за этого мы не можем использовать механизм из конструктора ArrayList-а и обходимся ручным выделением памяти и копированием:

public ArrayDeque(Collection<? extends E> c) {
  this(c.size());
  copyElements(c);
}

public ArrayDeque(int numElements) {
  elements = new Object[(numElements < 1) ? 1 :
      (numElements == Integer.MAX_VALUE) ? Integer.MAX_VALUE :
       numElements + 1];
}

private void copyElements(Collection<? extends E> c) {
  c.forEach(this::addLast);
}

И всё же в случае больших коллекций выигрыш есть хотя бы в разовом выделении нужного объёма памяти. "И где же здесь обещанная неочевидность?", — вопрошает читатель.

Неочевидность находится в классе jdk.internal.loader.URLClassPath. Попрошу пока не открывать его исходный код — там есть один комментарий, который я исключил:

URLClassPath(String cp, boolean skipEmptyElements) {
    ArrayList<URL> path = new ArrayList<>();
    //...

    // здесь был тот самый комментарий
    int size = path.size();
    ArrayDeque<URL> unopenedUrls = new ArrayDeque<>(size);
    for (int i = 0; i < size; i++)
        unopenedUrls.add(path.get(i));

    this.unopenedUrls = unopenedUrls;
    //...
}

На первый взгляд это идеальный кандидат на оптимизацию и ничто не помешает нам ужать 5 строк в 1:

this.unopenedUrls = new ArrayDeque<>(path);

Давайте вместе поразмышляем, может ли здесь что-то пойти нет так? Код очень простой и с точки зрения пользователя JDK преобразование выше полностью оправданно. И всё обстоит с точностью до наоборот с точки зрения разработчика JDK:

URLClassPath(String cp, boolean skipEmptyElements) {
    ArrayList<URL> path = new ArrayList<>();
    //...

    // can't use ArrayDeque#addAll or new ArrayDeque(Collection);
    // it's too early in the bootstrap to trigger use of lambdas
    int size = path.size();
    ArrayDeque<URL> unopenedUrls = new ArrayDeque<>(size);
    for (int i = 0; i < size; i++)
        unopenedUrls.add(path.get(i));

    this.unopenedUrls = unopenedUrls;
    //...
}

Лямбда (точнее ссылка на метод) находится в методе copyElements, использующемся в конструкторе ArrayDeque. Для пользователя JDK это не проблема, а для разработчика JDK это неприятность, ведь лямбды и ссылки на методы достаются небесплатно, их использование требует инфраструктурных затрат — существенных и очень нежелательных на ранних этапах загрузки виртуальной машины.

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

java -Xlog:class+init -version

Для собранного из исходников JDK имеем вот это:

Hidden text
[0.018s][info][class,init] 0 Initializing 'java/lang/Object'(no method) (0x0000000800000e60)
[0.018s][info][class,init] 1 Initializing 'java/lang/CharSequence'(no method) (0x0000000800009210)
[0.018s][info][class,init] 2 Initializing 'java/lang/String' (0x00000008000089b8)
[0.018s][info][class,init] 3 Initializing 'java/util/Comparator'(no method) (0x00000008000eb588)
[0.018s][info][class,init] 4 Initializing 'java/lang/String$CaseInsensitiveComparator'(no method) (0x000000080010dff8)
[0.018s][info][class,init] 5 Initializing 'java/lang/System' (0x0000000800002b68)
[0.019s][info][class,init] 6 Initializing 'java/lang/reflect/AnnotatedElement'(no method) (0x0000000800013cd0)
[0.019s][info][class,init] 7 Initializing 'java/lang/reflect/Type'(no method) (0x0000000800015210)
[0.019s][info][class,init] 8 Initializing 'java/lang/Class' (0x00000008000139e0)
[0.019s][info][class,init] 9 Initializing 'java/lang/ThreadGroup' (0x00000008000281b0)
[0.019s][info][class,init] 10 Initializing 'jdk/internal/misc/VM' (0x000000080000ac28)
[0.019s][info][class,init] 11 Initializing 'java/lang/Thread' (0x000000080000f370)
[0.019s][info][class,init] 12 Initializing 'java/security/AccessController' (0x00000008000631c8)
[0.019s][info][class,init] 13 Initializing 'java/security/AccessControlContext' (0x0000000800061b08)
[0.019s][info][class,init] 14 Initializing 'java/lang/Thread$FieldHolder'(no method) (0x00000008000278b0)
[0.019s][info][class,init] 15 Initializing 'java/lang/Module' (0x000000080001e8e0)
[0.019s][info][class,init] 16 Initializing 'java/lang/Module$ArchivedData' (0x000000080016c040)
[0.019s][info][class,init] 17 Initializing 'jdk/internal/misc/CDS' (0x0000000800035b90)
[0.019s][info][class,init] 18 Initializing 'java/lang/Iterable'(no method) (0x0000000800073d88)
[0.019s][info][class,init] 19 Initializing 'java/util/Collection'(no method) (0x00000008000741f8)
[0.019s][info][class,init] 20 Initializing 'java/util/AbstractCollection'(no method) (0x00000008000760e8)
[0.019s][info][class,init] 21 Initializing 'java/util/ImmutableCollections$AbstractImmutableCollection'(no method) (0x000000080015aed8)
[0.019s][info][class,init] 22 Initializing 'java/util/Set'(no method) (0x000000080000af30)
[0.019s][info][class,init] 23 Initializing 'java/util/ImmutableCollections$AbstractImmutableSet'(no method) (0x000000080015cc10)
[0.019s][info][class,init] 24 Initializing 'java/util/ImmutableCollections$Set12'(no method) (0x00000008001b53a0)
[0.019s][info][class,init] 25 Initializing 'jdk/internal/misc/UnsafeConstants' (0x000000080009a4a8)
[0.019s][info][class,init] 26 Initializing 'java/lang/reflect/AccessibleObject' (0x0000000800049da8)
[0.019s][info][class,init] 27 Initializing 'java/lang/reflect/ReflectAccess'(no method) (0x000000080016c608)
[0.019s][info][class,init] 28 Initializing 'jdk/internal/access/SharedSecrets'(no method) (0x0000000800004540)
[0.019s][info][class,init] 29 Initializing 'jdk/internal/reflect/ReflectionFactory$GetReflectionFactoryAction'(no method) (0x000000080011b780)
[0.019s][info][class,init] 30 Initializing 'jdk/internal/reflect/Reflection' (0x0000000800063be0)
[0.019s][info][class,init] 31 Initializing 'java/util/Objects'(no method) (0x0000000800072850)
[0.019s][info][class,init] 32 Initializing 'java/util/ImmutableCollections' (0x000000080015a2e0)
[0.019s][info][class,init] 33 Initializing 'java/util/List'(no method) (0x0000000800074d38)
[0.019s][info][class,init] 34 Initializing 'java/util/ImmutableCollections$AbstractImmutableList'(no method) (0x000000080015b240)
[0.019s][info][class,init] 35 Initializing 'java/util/ImmutableCollections$ListN'(no method) (0x000000080015c0c0)
[0.019s][info][class,init] 36 Initializing 'java/util/ImmutableCollections$SetN'(no method) (0x000000080015c810)
[0.020s][info][class,init] 37 Initializing 'java/util/Map'(no method) (0x00000008000048d0)
[0.020s][info][class,init] 38 Initializing 'java/util/AbstractMap'(no method) (0x000000080007f0c8)
[0.020s][info][class,init] 39 Initializing 'java/util/ImmutableCollections$AbstractImmutableMap'(no method) (0x000000080015d680)
[0.020s][info][class,init] 40 Initializing 'java/util/ImmutableCollections$MapN'(no method) (0x000000080015d2e8)
[0.020s][info][class,init] 41 Initializing 'java/lang/StringLatin1' (0x00000008000223c8)
[0.020s][info][class,init] 42 Initializing 'java/lang/Math' (0x0000000800022f18)
[0.020s][info][class,init] 43 Initializing 'java/lang/Number'(no method) (0x0000000800037aa8)
[0.020s][info][class,init] 44 Initializing 'java/lang/Float' (0x0000000800037838)
[0.020s][info][class,init] 45 Initializing 'java/lang/Double' (0x0000000800039308)
[0.020s][info][class,init] 46 Initializing 'jdk/internal/reflect/ReflectionFactory' (0x0000000800113bf8)
[0.020s][info][class,init] 47 Initializing 'java/lang/Record'(no method) (0x000000080007a218)
[0.020s][info][class,init] 48 Initializing 'jdk/internal/reflect/ReflectionFactory$Config'(no method) (0x00000008001be668)
[0.020s][info][class,init] 49 Initializing 'java/lang/ref/Reference' (0x00000008000460e8)
[0.020s][info][class,init] 50 Initializing 'java/lang/ref/Reference$1'(no method) (0x000000080013dd08)
[0.020s][info][class,init] 51 Initializing 'java/lang/reflect/Executable'(no method) (0x000000080004c1f0)
[0.020s][info][class,init] 52 Initializing 'java/lang/reflect/Method'(no method) (0x000000080004b7f0)
[0.020s][info][class,init] 53 Initializing 'java/lang/ref/FinalReference'(no method) (0x0000000800047e90)
[0.020s][info][class,init] 54 Initializing 'java/lang/ref/Finalizer' (0x00000008000487b8)
[0.020s][info][class,init] 55 Initializing 'java/lang/ref/ReferenceQueue' (0x0000000800049498)
[0.020s][info][class,init] 56 Initializing 'java/lang/ref/ReferenceQueue$Null'(no method) (0x00000008001bf578)
[0.020s][info][class,init] 57 Initializing 'java/lang/ref/NativeReferenceQueue'(no method) (0x0000000800049250)
[0.020s][info][class,init] 58 Initializing 'java/lang/ref/NativeReferenceQueue$Lock'(no method) (0x00000008001bedc0)
[0.020s][info][class,init] 59 Initializing 'java/lang/System$2'(no method) (0x00000008000104e0)
[0.020s][info][class,init] 60 Initializing 'jdk/internal/util/SystemProps' (0x0000000800006988)
[0.020s][info][class,init] 61 Initializing 'jdk/internal/util/SystemProps$Raw'(no method) (0x00000008001c00d8)
[0.029s][info][class,init] 62 Initializing 'java/util/HashMap'(no method) (0x00000008000abde0)
[0.029s][info][class,init] 63 Initializing 'java/lang/Integer' (0x000000080003d6d0)
[0.029s][info][class,init] 64 Initializing 'java/util/HashMap$Node'(no method) (0x00000008001c0a50)
[0.029s][info][class,init] 65 Initializing 'java/lang/StringConcatHelper' (0x0000000800023190)
[0.029s][info][class,init] 66 Initializing 'jdk/internal/misc/Unsafe' (0x000000080000dde8)
[0.030s][info][class,init] 67 Initializing 'java/lang/Byte' (0x000000080003a888)
[0.030s][info][class,init] 68 Initializing 'java/lang/VersionProps' (0x0000000800006b98)
[0.030s][info][class,init] 69 Initializing 'java/lang/Runtime' (0x000000080012d7c0)
[0.030s][info][class,init] 70 Initializing 'jdk/internal/util/Preconditions' (0x0000000800072f08)
[0.030s][info][class,init] 71 Initializing 'java/util/function/Function'(no method) (0x0000000800104360)
[0.030s][info][class,init] 72 Initializing 'jdk/internal/util/Preconditions$1'(no method) (0x00000008001c8a30)
[0.030s][info][class,init] 73 Initializing 'java/util/function/BiFunction'(no method) (0x0000000800159e68)
[0.030s][info][class,init] 74 Initializing 'jdk/internal/util/Preconditions$4'(no method) (0x00000008001c8578)
[0.030s][info][class,init] 75 Initializing 'jdk/internal/util/Preconditions$2'(no method) (0x00000008001c8e78)
[0.030s][info][class,init] 76 Initializing 'jdk/internal/util/Preconditions$3'(no method) (0x00000008001c92c0)
[0.030s][info][class,init] 77 Initializing 'java/util/Arrays' (0x00000008000233b8)
[0.030s][info][class,init] 78 Initializing 'java/lang/Character' (0x0000000800031c90)
[0.030s][info][class,init] 79 Initializing 'java/lang/CharacterData'(no method) (0x0000000800036220)
[0.030s][info][class,init] 80 Initializing 'java/lang/CharacterDataLatin1' (0x0000000800035ec0)
[0.030s][info][class,init] 81 Initializing 'java/util/Dictionary'(no method) (0x00000008000072b8)
[0.030s][info][class,init] 82 Initializing 'java/util/Hashtable'(no method) (0x00000008000074e8)
[0.030s][info][class,init] 83 Initializing 'java/util/Properties' (0x0000000800006e68)
[0.030s][info][class,init] 84 Initializing 'java/util/concurrent/ConcurrentMap'(no method) (0x0000000800080cd8)
[0.030s][info][class,init] 85 Initializing 'java/util/concurrent/ConcurrentHashMap' (0x000000080007eb30)
[0.030s][info][class,init] 86 Initializing 'java/io/ObjectStreamField'(no method) (0x000000080010cd20)
[0.030s][info][class,init] 87 Initializing 'java/util/AbstractSet'(no method) (0x0000000800100a68)
[0.030s][info][class,init] 88 Initializing 'java/util/HashMap$EntrySet'(no method) (0x00000008001c3548)
[0.030s][info][class,init] 89 Initializing 'java/util/HashMap$HashIterator'(no method) (0x00000008001c56c0)
[0.030s][info][class,init] 90 Initializing 'java/util/Iterator'(no method) (0x000000080000b1d8)
[0.030s][info][class,init] 91 Initializing 'java/util/HashMap$EntryIterator'(no method) (0x00000008001c5488)
[0.030s][info][class,init] 92 Initializing 'java/util/concurrent/ConcurrentHashMap$Node'(no method) (0x000000080019e128)
[0.031s][info][class,init] 93 Initializing 'java/nio/charset/Charset' (0x000000080000a190)
[0.031s][info][class,init] 94 Initializing 'java/nio/charset/spi/CharsetProvider'(no method) (0x00000008001d1260)
[0.031s][info][class,init] 95 Initializing 'sun/nio/cs/StandardCharsets' (0x00000008001d2088)
[0.031s][info][class,init] 96 Initializing 'sun/nio/cs/Unicode'(no method) (0x000000080000a3e0)
[0.031s][info][class,init] 97 Initializing 'sun/nio/cs/UTF_8' (0x0000000800009f20)
[0.031s][info][class,init] 98 Initializing 'jdk/internal/util/StaticProperty' (0x000000080000b858)
[0.031s][info][class,init] 99 Initializing 'sun/security/action/GetPropertyAction'(no method) (0x0000000800139ab8)
[0.031s][info][class,init] 100 Initializing 'java/io/InputStream'(no method) (0x000000080000bda8)
[0.031s][info][class,init] 101 Initializing 'java/io/FileInputStream' (0x000000080000bb00)
[0.031s][info][class,init] 102 Initializing 'java/io/FileDescriptor' (0x000000080000c5b8)
[0.031s][info][class,init] 103 Initializing 'java/io/FileDescriptor$1'(no method) (0x00000008001d4b88)
[0.031s][info][class,init] 104 Initializing 'java/io/OutputStream'(no method) (0x0000000800004f20)
[0.031s][info][class,init] 105 Initializing 'java/io/FileOutputStream' (0x000000080000c840)
[0.031s][info][class,init] 106 Initializing 'java/io/FilterInputStream'(no method) (0x000000080000cfc0)
[0.031s][info][class,init] 107 Initializing 'java/io/BufferedInputStream' (0x000000080000cd18)
[0.031s][info][class,init] 108 Initializing 'jdk/internal/misc/InternalLock' (0x000000080012ead0)
[0.031s][info][class,init] 109 Initializing 'java/util/concurrent/locks/ReentrantLock'(no method) (0x00000008001a16c0)
[0.031s][info][class,init] 110 Initializing 'java/util/concurrent/locks/AbstractOwnableSynchronizer'(no method) (0x000000080008bf20)
[0.031s][info][class,init] 111 Initializing 'java/util/concurrent/locks/AbstractQueuedSynchronizer' (0x00000008001ce8c8)
[0.031s][info][class,init] 112 Initializing 'java/util/concurrent/locks/ReentrantLock$Sync'(no method) (0x00000008001cf9f8)
[0.031s][info][class,init] 113 Initializing 'java/util/concurrent/locks/ReentrantLock$NonfairSync'(no method) (0x00000008001ce690)
[0.031s][info][class,init] 114 Initializing 'java/io/FilterOutputStream'(no method) (0x0000000800005188)
[0.031s][info][class,init] 115 Initializing 'java/io/PrintStream' (0x0000000800004b78)
[0.031s][info][class,init] 116 Initializing 'java/io/PrintStream$1'(no method) (0x00000008001d69c0)
[0.031s][info][class,init] 117 Initializing 'java/io/BufferedOutputStream'(no method) (0x0000000800009aa0)
[0.031s][info][class,init] 118 Initializing 'sun/nio/cs/US_ASCII' (0x00000008000e1d68)
[0.031s][info][class,init] 119 Initializing 'java/io/Writer'(no method) (0x00000008001509a0)
[0.031s][info][class,init] 120 Initializing 'java/io/OutputStreamWriter'(no method) (0x0000000800152068)
[0.031s][info][class,init] 121 Initializing 'sun/nio/cs/StreamEncoder' (0x00000008001d77d8)
[0.031s][info][class,init] 122 Initializing 'java/nio/charset/CharsetEncoder' (0x00000008000e2840)
[0.031s][info][class,init] 123 Initializing 'sun/nio/cs/US_ASCII$Encoder' (0x00000008001d6d50)
[0.031s][info][class,init] 124 Initializing 'java/nio/charset/CodingErrorAction' (0x00000008000e23c8)
[0.031s][info][class,init] 125 Initializing 'sun/nio/cs/Surrogate$Parser' (0x00000008001d9360)
[0.032s][info][class,init] 126 Initializing 'java/nio/charset/CoderResult' (0x00000008000ea620)
[0.032s][info][class,init] 127 Initializing 'java/nio/Buffer' (0x00000008000711b8)
[0.032s][info][class,init] 128 Initializing 'jdk/internal/misc/ScopedMemoryAccess' (0x000000080009a8d0)
[0.032s][info][class,init] 129 Initializing 'java/nio/Buffer$1'(no method) (0x00000008001ae650)
[0.032s][info][class,init] 130 Initializing 'java/nio/ByteBuffer' (0x00000008000e4100)
[0.032s][info][class,init] 131 Initializing 'java/nio/HeapByteBuffer' (0x00000008001deb80)
[0.032s][info][class,init] 132 Initializing 'java/nio/ByteOrder' (0x00000008001da348)
[0.032s][info][class,init] 133 Initializing 'java/io/BufferedWriter'(no method) (0x00000008001506b0)
[0.032s][info][class,init] 134 Initializing 'java/lang/Terminator' (0x000000080000d6f8)
[0.032s][info][class,init] 135 Initializing 'java/lang/Terminator$1'(no method) (0x00000008001e1d08)
[0.032s][info][class,init] 136 Initializing 'jdk/internal/misc/Signal' (0x00000008000776e0)
[0.032s][info][class,init] 137 Initializing 'java/lang/Integer$IntegerCache' (0x000000080003fef8)
[0.032s][info][class,init] 138 Initializing 'java/util/Hashtable$Entry'(no method) (0x00000008001586b8)
[0.032s][info][class,init] 139 Initializing 'jdk/internal/misc/Signal$Handler' (0x00000008001e1f20)
[0.032s][info][class,init] 140 Initializing 'jdk/internal/misc/Signal$NativeHandler'(no method) (0x00000008001e2478)
[0.032s][info][class,init] 141 Initializing 'jdk/internal/misc/OSEnvironment'(no method) (0x00000008001b4ca8)
[0.032s][info][class,init] 142 Initializing 'java/lang/Enum'(no method) (0x00000008000a9410)
[0.032s][info][class,init] 143 Initializing 'java/lang/Thread$State' (0x0000000800142c60)
[0.032s][info][class,init] 144 Initializing 'java/lang/ref/Reference$ReferenceHandler'(no method) (0x000000080013d830)
[0.032s][info][class,init] 145 Initializing 'java/lang/Thread$ThreadIdentifiers' (0x0000000800140590)
[0.033s][info][class,init] 146 Initializing 'java/lang/ref/Finalizer$FinalizerThread'(no method) (0x0000000800048ed8)
[0.033s][info][class,init] 147 Initializing 'java/lang/ref/PhantomReference'(no method) (0x0000000800048348)
[0.033s][info][class,init] 148 Initializing 'java/lang/Throwable' (0x000000080002e058)
[0.033s][info][class,init] 149 Initializing 'jdk/internal/ref/Cleaner' (0x000000080013d118)
[0.033s][info][class,init] 150 Initializing 'jdk/internal/misc/Blocker' (0x00000008000e1620)
[0.033s][info][class,init] 151 Initializing 'java/util/concurrent/locks/AbstractQueuedSynchronizer$ConditionObject'(no method) (0x00000008001d0390)
[0.033s][info][class,init] 152 Initializing 'java/util/Collections' (0x00000008000b4088)
[0.033s][info][class,init] 153 Initializing 'java/util/Collections$EmptySet'(no method) (0x00000008001f0b38)
[0.033s][info][class,init] 154 Initializing 'java/util/AbstractList'(no method) (0x00000008000738c8)
[0.033s][info][class,init] 155 Initializing 'java/util/Collections$EmptyList'(no method) (0x00000008001f15c0)
[0.033s][info][class,init] 156 Initializing 'java/util/Collections$EmptyMap'(no method) (0x00000008001f23f8)
[0.033s][info][class,init] 157 Initializing 'java/lang/Error'(no method) (0x000000080002fd20)
[0.033s][info][class,init] 158 Initializing 'java/lang/VirtualMachineError'(no method) (0x0000000800089268)
[0.033s][info][class,init] 159 Initializing 'java/lang/OutOfMemoryError'(no method) (0x000000080008a310)
[0.033s][info][class,init] 160 Initializing 'java/lang/Exception'(no method) (0x0000000800084dd0)
[0.033s][info][class,init] 161 Initializing 'java/lang/RuntimeException'(no method) (0x0000000800085308)
[0.033s][info][class,init] 162 Initializing 'java/lang/NullPointerException'(no method) (0x0000000800088680)
[0.033s][info][class,init] 163 Initializing 'java/lang/ClassCastException'(no method) (0x0000000800085d80)
[0.033s][info][class,init] 164 Initializing 'java/lang/ArrayStoreException'(no method) (0x00000008000859b8)
[0.033s][info][class,init] 165 Initializing 'java/lang/ArithmeticException'(no method) (0x0000000800084b80)
[0.033s][info][class,init] 166 Initializing 'java/lang/StackOverflowError'(no method) (0x000000080008a8b8)
[0.033s][info][class,init] 167 Initializing 'java/lang/IllegalMonitorStateException'(no method) (0x00000008000871f0)
[0.033s][info][class,init] 168 Initializing 'java/lang/IllegalArgumentException'(no method) (0x0000000800086d30)
[0.034s][info][class,init] 169 Initializing 'java/lang/invoke/MethodHandle' (0x00000008000a9fa0)
[0.034s][info][class,init] 170 Initializing 'java/lang/invoke/MethodHandleStatics' (0x00000008000a9a70)
[0.034s][info][class,init] 171 Initializing 'java/lang/Boolean' (0x0000000800030fb8)
[0.034s][info][class,init] 172 Initializing 'java/lang/invoke/ResolvedMethodName'(no method) (0x00000008000c82a8)
[0.034s][info][class,init] 173 Initializing 'java/lang/invoke/MemberName' (0x00000008000c4970)
[0.034s][info][class,init] 174 Initializing 'java/lang/invoke/MethodHandleNatives' (0x00000008000c85a0)
[0.034s][info][class,init] 175 Initializing 'jdk/internal/module/ModuleBootstrap' (0x000000080000db00)
[0.034s][info][class,init] 176 Initializing 'java/lang/invoke/MethodHandles' (0x00000008000b2900)
[0.034s][info][class,init] 177 Initializing 'java/lang/invoke/MemberName$Factory' (0x000000080016f250)
[0.034s][info][class,init] 178 Initializing 'java/lang/invoke/MethodHandles$Lookup' (0x00000008000b4318)
[0.034s][info][class,init] 179 Initializing 'java/lang/StrictMath' (0x000000080008c300)
[0.034s][info][class,init] 180 Initializing 'java/util/ImmutableCollections$MapN$1'(no method) (0x00000008001b6b80)
[0.035s][info][class,init] 181 Initializing 'java/util/ImmutableCollections$MapN$MapNIterator'(no method) (0x00000008001b64e0)
[0.035s][info][class,init] 182 Initializing 'java/util/KeyValueHolder'(no method) (0x000000080015eed8)
[0.035s][info][class,init] 183 Initializing 'sun/invoke/util/VerifyAccess' (0x0000000800171958)
[0.035s][info][class,init] 184 Initializing 'java/lang/reflect/Modifier'(no method) (0x0000000800111a58)
[0.035s][info][class,init] 185 Initializing 'java/lang/module/ModuleDescriptor' (0x0000000800116ca0)
[0.035s][info][class,init] 186 Initializing 'java/lang/module/ModuleDescriptor$1'(no method) (0x00000008001feed0)
[0.035s][info][class,init] 187 Initializing 'java/io/File' (0x000000080006d560)
[0.035s][info][class,init] 188 Initializing 'java/io/DefaultFileSystem'(no method) (0x000000080020a2f0)
[0.035s][info][class,init] 189 Initializing 'java/io/FileSystem' (0x0000000800207978)
[0.035s][info][class,init] 190 Initializing 'java/io/UnixFileSystem' (0x000000080020a598)
[0.035s][info][class,init] 191 Initializing 'java/lang/AbstractStringBuilder' (0x00000008000572d8)
[0.035s][info][class,init] 192 Initializing 'java/lang/StringBuilder'(no method) (0x000000080005c620)
[0.035s][info][class,init] 193 Initializing 'jdk/internal/util/ArraysSupport' (0x0000000800095a20)
[0.035s][info][class,init] 194 Initializing 'jdk/internal/module/ModulePatcher' (0x000000080019acf8)
[0.035s][info][class,init] 195 Initializing 'java/util/HashSet' (0x0000000800100668)
[0.035s][info][class,init] 196 Initializing 'jdk/internal/module/ModuleBootstrap$Counters' (0x00000008001f37a8)
[0.035s][info][class,init] 197 Initializing 'jdk/internal/module/ArchivedBootLayer' (0x00000008001f4058)
[0.035s][info][class,init] 198 Initializing 'java/lang/ModuleLayer' (0x0000000800135690)
[0.035s][info][class,init] 199 Initializing 'java/lang/module/Configuration' (0x0000000800160768)
[0.035s][info][class,init] 200 Initializing 'jdk/internal/loader/AbstractClassLoaderValue' (0x000000080022fe90)
[0.035s][info][class,init] 201 Initializing 'jdk/internal/loader/ClassLoaderValue'(no method) (0x000000080022fc58)
[0.035s][info][class,init] 202 Initializing 'java/util/ImmutableCollections$List12'(no method) (0x000000080015aa10)
[0.035s][info][class,init] 203 Initializing 'java/lang/module/ResolvedModule'(no method) (0x0000000800161dd8)
[0.035s][info][class,init] 204 Initializing 'java/lang/module/ModuleReference'(no method) (0x00000008001627b0)
[0.035s][info][class,init] 205 Initializing 'jdk/internal/module/ModuleReferenceImpl'(no method) (0x00000008001f6ac8)
[0.035s][info][class,init] 206 Initializing 'java/lang/module/ModuleDescriptor$Version'(no method) (0x000000080015f618)
[0.035s][info][class,init] 207 Initializing 'java/util/ArrayList' (0x00000008000dec90)
[0.035s][info][class,init] 208 Initializing 'java/lang/module/ModuleDescriptor$Requires' (0x0000000800200328)
[0.035s][info][class,init] 209 Initializing 'java/lang/module/ModuleDescriptor$Provides'(no method) (0x00000008001ff900)
[0.035s][info][class,init] 210 Initializing 'java/net/URI' (0x0000000800162e58)
[0.036s][info][class,init] 211 Initializing 'java/net/URI$1'(no method) (0x00000008002164e0)
[0.036s][info][class,init] 212 Initializing 'jdk/internal/module/SystemModuleFinders$2'(no method) (0x00000008001f67d0)
[0.036s][info][class,init] 213 Initializing 'jdk/internal/module/SystemModuleFinders$3'(no method) (0x00000008001f70f0)
[0.036s][info][class,init] 214 Initializing 'java/lang/module/ModuleDescriptor$Exports'(no method) (0x0000000800137fd8)
[0.036s][info][class,init] 215 Initializing 'jdk/internal/module/ModuleTarget'(no method) (0x00000008002114d8)
[0.036s][info][class,init] 216 Initializing 'jdk/internal/module/ModuleHashes'(no method) (0x00000008001f62c8)
[0.036s][info][class,init] 217 Initializing 'java/util/Collections$UnmodifiableMap'(no method) (0x00000008001e68c8)
[0.036s][info][class,init] 218 Initializing 'java/lang/module/ModuleDescriptor$Opens'(no method) (0x0000000800137430)
[0.036s][info][class,init] 219 Initializing 'java/lang/ClassLoader' (0x000000080000e418)
[0.036s][info][class,init] 220 Initializing 'java/security/SecureClassLoader' (0x0000000800066f80)
[0.036s][info][class,init] 221 Initializing 'java/lang/ClassLoader$ParallelLoaders' (0x00000008001265b8)
[0.036s][info][class,init] 222 Initializing 'java/util/WeakHashMap' (0x0000000800122e68)
[0.036s][info][class,init] 223 Initializing 'java/util/Collections$SetFromMap'(no method) (0x00000008001ee308)
[0.036s][info][class,init] 224 Initializing 'java/util/WeakHashMap$KeySet'(no method) (0x0000000800221210)
[0.036s][info][class,init] 225 Initializing 'java/lang/ref/WeakReference'(no method) (0x0000000800047910)
[0.036s][info][class,init] 226 Initializing 'java/util/WeakHashMap$Entry'(no method) (0x0000000800220818)
[0.036s][info][class,init] 227 Initializing 'jdk/internal/loader/BuiltinClassLoader' (0x00000008000816a0)
[0.036s][info][class,init] 228 Initializing 'jdk/internal/loader/ArchivedClassLoaders' (0x00000008000ddba8)
[0.036s][info][class,init] 229 Initializing 'jdk/internal/loader/ClassLoaders$BootClassLoader'(no method) (0x00000008000ddfd8)
[0.036s][info][class,init] 230 Initializing 'java/security/ProtectionDomain' (0x0000000800065d08)
[0.036s][info][class,init] 231 Initializing 'java/security/ProtectionDomain$JavaSecurityAccessImpl'(no method) (0x000000080013a1b8)
[0.036s][info][class,init] 232 Initializing 'java/security/CodeSource'(no method) (0x0000000800064958)
[0.036s][info][class,init] 233 Initializing 'java/security/Principal'(no method) (0x0000000800138e68)
[0.036s][info][class,init] 234 Initializing 'java/security/ProtectionDomain$Key'(no method) (0x0000000800138b80)
[0.036s][info][class,init] 235 Initializing 'jdk/internal/loader/NativeLibraries' (0x000000080007dd78)
[0.036s][info][class,init] 236 Initializing 'jdk/internal/loader/ClassLoaderHelper' (0x0000000800080ec8)
[0.036s][info][class,init] 237 Initializing 'java/util/concurrent/ConcurrentHashMap$CollectionView'(no method) (0x0000000800157490)
[0.036s][info][class,init] 238 Initializing 'java/util/concurrent/ConcurrentHashMap$KeySetView'(no method) (0x00000008001570c0)
[0.036s][info][class,init] 239 Initializing 'jdk/internal/loader/ClassLoaders$PlatformClassLoader' (0x00000008000846a0)
[0.036s][info][class,init] 240 Initializing 'jdk/internal/module/ServicesCatalog' (0x0000000800112fe8)
[0.036s][info][class,init] 241 Initializing 'java/util/concurrent/CopyOnWriteArrayList'(no method) (0x000000080022ccf8)
[0.036s][info][class,init] 242 Initializing 'jdk/internal/module/ServicesCatalog$ServiceProvider'(no method) (0x000000080022f570)
[0.036s][info][class,init] 243 Initializing 'jdk/internal/loader/BuiltinClassLoader$LoadedModule'(no method) (0x0000000800198438)
[0.036s][info][class,init] 244 Initializing 'jdk/internal/loader/ClassLoaders$AppClassLoader' (0x0000000800083e30)
[0.036s][info][class,init] 245 Initializing 'jdk/internal/loader/BootLoader' (0x00000008001126a0)
[0.036s][info][class,init] 246 Initializing 'jdk/internal/loader/ClassLoaders' (0x00000008000dd4c0)
[0.036s][info][class,init] 247 Initializing 'jdk/internal/loader/URLClassPath' (0x00000008000de360)
[0.036s][info][class,init] 248 Initializing 'java/net/URL' (0x0000000800067848)
[0.036s][info][class,init] 249 Initializing 'java/net/URL$DefaultFactory' (0x000000080018d4a8)
[0.036s][info][class,init] 250 Initializing 'java/net/URL$3'(no method) (0x000000080018da88)
[0.036s][info][class,init] 251 Initializing 'java/io/File$PathStatus' (0x00000008002089b8)
[0.037s][info][class,init] 252 Initializing 'sun/net/www/ParseUtil' (0x00000008000785d8)
[0.037s][info][class,init] 253 Initializing 'java/util/HexFormat' (0x0000000800079520)
[0.037s][info][class,init] 254 Initializing 'java/net/URLStreamHandler'(no method) (0x000000080018c1c0)
[0.037s][info][class,init] 255 Initializing 'sun/net/www/protocol/file/Handler'(no method) (0x0000000800228420)
[0.037s][info][class,init] 256 Initializing 'sun/net/util/IPAddressUtil' (0x000000080018a918)
[0.037s][info][class,init] 257 Initializing 'java/util/ArrayDeque'(no method) (0x0000000800221a40)
[0.037s][info][class,init] 258 Initializing 'java/lang/invoke/StringConcatFactory' (0x000000080000e0e8)
[0.037s][info][class,init] 259 Initializing 'java/lang/invoke/StringConcatFactory$1'(no method) (0x0000000800234cc8)
[0.037s][info][class,init] 260 Initializing 'java/lang/invoke/StringConcatFactory$2'(no method) (0x0000000800235208)
[0.037s][info][class,init] 261 Initializing 'java/lang/invoke/StringConcatFactory$3'(no method) (0x00000008002356e0)
[0.038s][info][class,init] 262 Initializing 'java/nio/CharBuffer' (0x00000008000e7330)
[0.038s][info][class,init] 263 Initializing 'java/nio/HeapCharBuffer' (0x000000080026cd00)
[0.038s][info][class,init] 264 Initializing 'java/lang/StringCoding'(no method) (0x000000080008f4c0)
[0.038s][info][class,init] 265 Initializing 'java/lang/Shutdown' (0x00000008000457e0)
[0.038s][info][class,init] 266 Initializing 'java/lang/Shutdown$Lock'(no method) (0x000000080023a838)

После "улучшения" кода URLClassPath эта же команда выдаст существенно более длинный список:

Hidden text
[0.016s][info][class,init] 0 Initializing 'java/lang/Object'(no method) (0x0000000800000e60)
[0.016s][info][class,init] 1 Initializing 'java/lang/CharSequence'(no method) (0x0000000800009210)
[0.016s][info][class,init] 2 Initializing 'java/lang/String' (0x00000008000089b8)
[0.016s][info][class,init] 3 Initializing 'java/util/Comparator'(no method) (0x00000008000eb588)
[0.016s][info][class,init] 4 Initializing 'java/lang/String$CaseInsensitiveComparator'(no method) (0x000000080010dff8)
[0.016s][info][class,init] 5 Initializing 'java/lang/System' (0x0000000800002b68)
[0.016s][info][class,init] 6 Initializing 'java/lang/reflect/AnnotatedElement'(no method) (0x0000000800013cd0)
[0.016s][info][class,init] 7 Initializing 'java/lang/reflect/Type'(no method) (0x0000000800015210)
[0.016s][info][class,init] 8 Initializing 'java/lang/Class' (0x00000008000139e0)
[0.016s][info][class,init] 9 Initializing 'java/lang/ThreadGroup' (0x00000008000281b0)
[0.016s][info][class,init] 10 Initializing 'jdk/internal/misc/VM' (0x000000080000ac28)
[0.017s][info][class,init] 11 Initializing 'java/lang/Thread' (0x000000080000f370)
[0.017s][info][class,init] 12 Initializing 'java/security/AccessController' (0x00000008000631c8)
[0.017s][info][class,init] 13 Initializing 'java/security/AccessControlContext' (0x0000000800061b08)
[0.017s][info][class,init] 14 Initializing 'java/lang/Thread$FieldHolder'(no method) (0x00000008000278b0)
[0.017s][info][class,init] 15 Initializing 'java/lang/Module' (0x000000080001e8e0)
[0.017s][info][class,init] 16 Initializing 'java/lang/Module$ArchivedData' (0x000000080016c040)
[0.017s][info][class,init] 17 Initializing 'jdk/internal/misc/CDS' (0x0000000800035b90)
[0.017s][info][class,init] 18 Initializing 'java/lang/Iterable'(no method) (0x0000000800073d88)
[0.017s][info][class,init] 19 Initializing 'java/util/Collection'(no method) (0x00000008000741f8)
[0.017s][info][class,init] 20 Initializing 'java/util/AbstractCollection'(no method) (0x00000008000760e8)
[0.017s][info][class,init] 21 Initializing 'java/util/ImmutableCollections$AbstractImmutableCollection'(no method) (0x000000080015aed8)
[0.017s][info][class,init] 22 Initializing 'java/util/Set'(no method) (0x000000080000af30)
[0.017s][info][class,init] 23 Initializing 'java/util/ImmutableCollections$AbstractImmutableSet'(no method) (0x000000080015cc10)
[0.017s][info][class,init] 24 Initializing 'java/util/ImmutableCollections$Set12'(no method) (0x00000008001b53a0)
[0.017s][info][class,init] 25 Initializing 'jdk/internal/misc/UnsafeConstants' (0x000000080009a4a8)
[0.017s][info][class,init] 26 Initializing 'java/lang/reflect/AccessibleObject' (0x0000000800049da8)
[0.017s][info][class,init] 27 Initializing 'java/lang/reflect/ReflectAccess'(no method) (0x000000080016c608)
[0.017s][info][class,init] 28 Initializing 'jdk/internal/access/SharedSecrets'(no method) (0x0000000800004540)
[0.017s][info][class,init] 29 Initializing 'jdk/internal/reflect/ReflectionFactory$GetReflectionFactoryAction'(no method) (0x000000080011b780)
[0.018s][info][class,init] 30 Initializing 'jdk/internal/reflect/Reflection' (0x0000000800063be0)
[0.018s][info][class,init] 31 Initializing 'java/util/Objects'(no method) (0x0000000800072850)
[0.018s][info][class,init] 32 Initializing 'java/util/ImmutableCollections' (0x000000080015a2e0)
[0.018s][info][class,init] 33 Initializing 'java/util/List'(no method) (0x0000000800074d38)
[0.018s][info][class,init] 34 Initializing 'java/util/ImmutableCollections$AbstractImmutableList'(no method) (0x000000080015b240)
[0.018s][info][class,init] 35 Initializing 'java/util/ImmutableCollections$ListN'(no method) (0x000000080015c0c0)
[0.018s][info][class,init] 36 Initializing 'java/util/ImmutableCollections$SetN'(no method) (0x000000080015c810)
[0.018s][info][class,init] 37 Initializing 'java/util/Map'(no method) (0x00000008000048d0)
[0.018s][info][class,init] 38 Initializing 'java/util/AbstractMap'(no method) (0x000000080007f0c8)
[0.018s][info][class,init] 39 Initializing 'java/util/ImmutableCollections$AbstractImmutableMap'(no method) (0x000000080015d680)
[0.018s][info][class,init] 40 Initializing 'java/util/ImmutableCollections$MapN'(no method) (0x000000080015d2e8)
[0.018s][info][class,init] 41 Initializing 'java/lang/StringLatin1' (0x00000008000223c8)
[0.018s][info][class,init] 42 Initializing 'java/lang/Math' (0x0000000800022f18)
[0.018s][info][class,init] 43 Initializing 'java/lang/Number'(no method) (0x0000000800037aa8)
[0.018s][info][class,init] 44 Initializing 'java/lang/Float' (0x0000000800037838)
[0.018s][info][class,init] 45 Initializing 'java/lang/Double' (0x0000000800039308)
[0.018s][info][class,init] 46 Initializing 'jdk/internal/reflect/ReflectionFactory' (0x0000000800113bf8)
[0.018s][info][class,init] 47 Initializing 'java/lang/Record'(no method) (0x000000080007a218)
[0.018s][info][class,init] 48 Initializing 'jdk/internal/reflect/ReflectionFactory$Config'(no method) (0x00000008001be668)
[0.018s][info][class,init] 49 Initializing 'java/lang/ref/Reference' (0x00000008000460e8)
[0.018s][info][class,init] 50 Initializing 'java/lang/ref/Reference$1'(no method) (0x000000080013dd08)
[0.018s][info][class,init] 51 Initializing 'java/lang/reflect/Executable'(no method) (0x000000080004c1f0)
[0.018s][info][class,init] 52 Initializing 'java/lang/reflect/Method'(no method) (0x000000080004b7f0)
[0.018s][info][class,init] 53 Initializing 'java/lang/ref/FinalReference'(no method) (0x0000000800047e90)
[0.018s][info][class,init] 54 Initializing 'java/lang/ref/Finalizer' (0x00000008000487b8)
[0.019s][info][class,init] 55 Initializing 'java/lang/ref/ReferenceQueue' (0x0000000800049498)
[0.019s][info][class,init] 56 Initializing 'java/lang/ref/ReferenceQueue$Null'(no method) (0x00000008001bf578)
[0.019s][info][class,init] 57 Initializing 'java/lang/ref/NativeReferenceQueue'(no method) (0x0000000800049250)
[0.019s][info][class,init] 58 Initializing 'java/lang/ref/NativeReferenceQueue$Lock'(no method) (0x00000008001bedc0)
[0.019s][info][class,init] 59 Initializing 'java/lang/System$2'(no method) (0x00000008000104e0)
[0.019s][info][class,init] 60 Initializing 'jdk/internal/util/SystemProps' (0x0000000800006988)
[0.019s][info][class,init] 61 Initializing 'jdk/internal/util/SystemProps$Raw'(no method) (0x00000008001c00d8)
[0.027s][info][class,init] 62 Initializing 'java/util/HashMap'(no method) (0x00000008000abde0)
[0.027s][info][class,init] 63 Initializing 'java/lang/Integer' (0x000000080003d6d0)
[0.027s][info][class,init] 64 Initializing 'java/util/HashMap$Node'(no method) (0x00000008001c0a50)
[0.028s][info][class,init] 65 Initializing 'java/lang/StringConcatHelper' (0x0000000800023190)
[0.028s][info][class,init] 66 Initializing 'jdk/internal/misc/Unsafe' (0x000000080000dde8)
[0.028s][info][class,init] 67 Initializing 'java/lang/Byte' (0x000000080003a888)
[0.028s][info][class,init] 68 Initializing 'java/lang/VersionProps' (0x0000000800006b98)
[0.028s][info][class,init] 69 Initializing 'java/lang/Runtime' (0x000000080012d7c0)
[0.028s][info][class,init] 70 Initializing 'jdk/internal/util/Preconditions' (0x0000000800072f08)
[0.028s][info][class,init] 71 Initializing 'java/util/function/Function'(no method) (0x0000000800104360)
[0.028s][info][class,init] 72 Initializing 'jdk/internal/util/Preconditions$1'(no method) (0x00000008001c8a30)
[0.028s][info][class,init] 73 Initializing 'java/util/function/BiFunction'(no method) (0x0000000800159e68)
[0.028s][info][class,init] 74 Initializing 'jdk/internal/util/Preconditions$4'(no method) (0x00000008001c8578)
[0.028s][info][class,init] 75 Initializing 'jdk/internal/util/Preconditions$2'(no method) (0x00000008001c8e78)
[0.028s][info][class,init] 76 Initializing 'jdk/internal/util/Preconditions$3'(no method) (0x00000008001c92c0)
[0.028s][info][class,init] 77 Initializing 'java/util/Arrays' (0x00000008000233b8)
[0.028s][info][class,init] 78 Initializing 'java/lang/Character' (0x0000000800031c90)
[0.028s][info][class,init] 79 Initializing 'java/lang/CharacterData'(no method) (0x0000000800036220)
[0.028s][info][class,init] 80 Initializing 'java/lang/CharacterDataLatin1' (0x0000000800035ec0)
[0.028s][info][class,init] 81 Initializing 'java/util/Dictionary'(no method) (0x00000008000072b8)
[0.028s][info][class,init] 82 Initializing 'java/util/Hashtable'(no method) (0x00000008000074e8)
[0.028s][info][class,init] 83 Initializing 'java/util/Properties' (0x0000000800006e68)
[0.028s][info][class,init] 84 Initializing 'java/util/concurrent/ConcurrentMap'(no method) (0x0000000800080cd8)
[0.028s][info][class,init] 85 Initializing 'java/util/concurrent/ConcurrentHashMap' (0x000000080007eb30)
[0.028s][info][class,init] 86 Initializing 'java/io/ObjectStreamField'(no method) (0x000000080010cd20)
[0.029s][info][class,init] 87 Initializing 'java/util/AbstractSet'(no method) (0x0000000800100a68)
[0.029s][info][class,init] 88 Initializing 'java/util/HashMap$EntrySet'(no method) (0x00000008001c3548)
[0.029s][info][class,init] 89 Initializing 'java/util/HashMap$HashIterator'(no method) (0x00000008001c56c0)
[0.029s][info][class,init] 90 Initializing 'java/util/Iterator'(no method) (0x000000080000b1d8)
[0.029s][info][class,init] 91 Initializing 'java/util/HashMap$EntryIterator'(no method) (0x00000008001c5488)
[0.029s][info][class,init] 92 Initializing 'java/util/concurrent/ConcurrentHashMap$Node'(no method) (0x000000080019e128)
[0.029s][info][class,init] 93 Initializing 'java/nio/charset/Charset' (0x000000080000a190)
[0.029s][info][class,init] 94 Initializing 'java/nio/charset/spi/CharsetProvider'(no method) (0x00000008001d1260)
[0.029s][info][class,init] 95 Initializing 'sun/nio/cs/StandardCharsets' (0x00000008001d2088)
[0.029s][info][class,init] 96 Initializing 'sun/nio/cs/Unicode'(no method) (0x000000080000a3e0)
[0.029s][info][class,init] 97 Initializing 'sun/nio/cs/UTF_8' (0x0000000800009f20)
[0.029s][info][class,init] 98 Initializing 'jdk/internal/util/StaticProperty' (0x000000080000b858)
[0.029s][info][class,init] 99 Initializing 'sun/security/action/GetPropertyAction'(no method) (0x0000000800139ab8)
[0.029s][info][class,init] 100 Initializing 'java/io/InputStream'(no method) (0x000000080000bda8)
[0.029s][info][class,init] 101 Initializing 'java/io/FileInputStream' (0x000000080000bb00)
[0.029s][info][class,init] 102 Initializing 'java/io/FileDescriptor' (0x000000080000c5b8)
[0.029s][info][class,init] 103 Initializing 'java/io/FileDescriptor$1'(no method) (0x00000008001d4b88)
[0.029s][info][class,init] 104 Initializing 'java/io/OutputStream'(no method) (0x0000000800004f20)
[0.029s][info][class,init] 105 Initializing 'java/io/FileOutputStream' (0x000000080000c840)
[0.029s][info][class,init] 106 Initializing 'java/io/FilterInputStream'(no method) (0x000000080000cfc0)
[0.029s][info][class,init] 107 Initializing 'java/io/BufferedInputStream' (0x000000080000cd18)
[0.029s][info][class,init] 108 Initializing 'jdk/internal/misc/InternalLock' (0x000000080012ead0)
[0.029s][info][class,init] 109 Initializing 'java/util/concurrent/locks/ReentrantLock'(no method) (0x00000008001a16c0)
[0.029s][info][class,init] 110 Initializing 'java/util/concurrent/locks/AbstractOwnableSynchronizer'(no method) (0x000000080008bf20)
[0.029s][info][class,init] 111 Initializing 'java/util/concurrent/locks/AbstractQueuedSynchronizer' (0x00000008001ce8c8)
[0.029s][info][class,init] 112 Initializing 'java/util/concurrent/locks/ReentrantLock$Sync'(no method) (0x00000008001cf9f8)
[0.029s][info][class,init] 113 Initializing 'java/util/concurrent/locks/ReentrantLock$NonfairSync'(no method) (0x00000008001ce690)
[0.029s][info][class,init] 114 Initializing 'java/io/FilterOutputStream'(no method) (0x0000000800005188)
[0.030s][info][class,init] 115 Initializing 'java/io/PrintStream' (0x0000000800004b78)
[0.030s][info][class,init] 116 Initializing 'java/io/PrintStream$1'(no method) (0x00000008001d69c0)
[0.030s][info][class,init] 117 Initializing 'java/io/BufferedOutputStream'(no method) (0x0000000800009aa0)
[0.030s][info][class,init] 118 Initializing 'sun/nio/cs/US_ASCII' (0x00000008000e1d68)
[0.030s][info][class,init] 119 Initializing 'java/io/Writer'(no method) (0x00000008001509a0)
[0.030s][info][class,init] 120 Initializing 'java/io/OutputStreamWriter'(no method) (0x0000000800152068)
[0.030s][info][class,init] 121 Initializing 'sun/nio/cs/StreamEncoder' (0x00000008001d77d8)
[0.030s][info][class,init] 122 Initializing 'java/nio/charset/CharsetEncoder' (0x00000008000e2840)
[0.030s][info][class,init] 123 Initializing 'sun/nio/cs/US_ASCII$Encoder' (0x00000008001d6d50)
[0.030s][info][class,init] 124 Initializing 'java/nio/charset/CodingErrorAction' (0x00000008000e23c8)
[0.030s][info][class,init] 125 Initializing 'sun/nio/cs/Surrogate$Parser' (0x00000008001d9360)
[0.030s][info][class,init] 126 Initializing 'java/nio/charset/CoderResult' (0x00000008000ea620)
[0.030s][info][class,init] 127 Initializing 'java/nio/Buffer' (0x00000008000711b8)
[0.030s][info][class,init] 128 Initializing 'jdk/internal/misc/ScopedMemoryAccess' (0x000000080009a8d0)
[0.030s][info][class,init] 129 Initializing 'java/nio/Buffer$1'(no method) (0x00000008001ae650)
[0.030s][info][class,init] 130 Initializing 'java/nio/ByteBuffer' (0x00000008000e4100)
[0.030s][info][class,init] 131 Initializing 'java/nio/HeapByteBuffer' (0x00000008001deb80)
[0.030s][info][class,init] 132 Initializing 'java/nio/ByteOrder' (0x00000008001da348)
[0.030s][info][class,init] 133 Initializing 'java/io/BufferedWriter'(no method) (0x00000008001506b0)
[0.030s][info][class,init] 134 Initializing 'java/lang/Terminator' (0x000000080000d6f8)
[0.030s][info][class,init] 135 Initializing 'java/lang/Terminator$1'(no method) (0x00000008001e1d08)
[0.030s][info][class,init] 136 Initializing 'jdk/internal/misc/Signal' (0x00000008000776e0)
[0.031s][info][class,init] 137 Initializing 'java/lang/Integer$IntegerCache' (0x000000080003fef8)
[0.031s][info][class,init] 138 Initializing 'java/util/Hashtable$Entry'(no method) (0x00000008001586b8)
[0.031s][info][class,init] 139 Initializing 'jdk/internal/misc/Signal$Handler' (0x00000008001e1f20)
[0.031s][info][class,init] 140 Initializing 'jdk/internal/misc/Signal$NativeHandler'(no method) (0x00000008001e2478)
[0.031s][info][class,init] 141 Initializing 'jdk/internal/misc/OSEnvironment'(no method) (0x00000008001b4ca8)
[0.031s][info][class,init] 142 Initializing 'java/lang/Enum'(no method) (0x00000008000a9410)
[0.031s][info][class,init] 143 Initializing 'java/lang/Thread$State' (0x0000000800142c60)
[0.031s][info][class,init] 144 Initializing 'java/lang/ref/Reference$ReferenceHandler'(no method) (0x000000080013d830)
[0.031s][info][class,init] 145 Initializing 'java/lang/Thread$ThreadIdentifiers' (0x0000000800140590)
[0.031s][info][class,init] 146 Initializing 'java/lang/ref/Finalizer$FinalizerThread'(no method) (0x0000000800048ed8)
[0.031s][info][class,init] 147 Initializing 'java/lang/ref/PhantomReference'(no method) (0x0000000800048348)
[0.031s][info][class,init] 148 Initializing 'jdk/internal/ref/Cleaner' (0x000000080013d118)
[0.031s][info][class,init] 149 Initializing 'java/util/concurrent/locks/AbstractQueuedSynchronizer$ConditionObject'(no method) (0x00000008001d0390)
[0.031s][info][class,init] 150 Initializing 'java/lang/Throwable' (0x000000080002e058)
[0.031s][info][class,init] 151 Initializing 'jdk/internal/misc/Blocker' (0x00000008000e1620)
[0.031s][info][class,init] 152 Initializing 'java/util/Collections' (0x00000008000b4088)
[0.031s][info][class,init] 153 Initializing 'java/util/Collections$EmptySet'(no method) (0x00000008001f0b38)
[0.031s][info][class,init] 154 Initializing 'java/util/AbstractList'(no method) (0x00000008000738c8)
[0.031s][info][class,init] 155 Initializing 'java/util/Collections$EmptyList'(no method) (0x00000008001f15c0)
[0.031s][info][class,init] 156 Initializing 'java/util/Collections$EmptyMap'(no method) (0x00000008001f23f8)
[0.031s][info][class,init] 157 Initializing 'java/lang/Error'(no method) (0x000000080002fd20)
[0.031s][info][class,init] 158 Initializing 'java/lang/VirtualMachineError'(no method) (0x0000000800089268)
[0.031s][info][class,init] 159 Initializing 'java/lang/OutOfMemoryError'(no method) (0x000000080008a310)
[0.031s][info][class,init] 160 Initializing 'java/lang/Exception'(no method) (0x0000000800084dd0)
[0.031s][info][class,init] 161 Initializing 'java/lang/RuntimeException'(no method) (0x0000000800085308)
[0.031s][info][class,init] 162 Initializing 'java/lang/NullPointerException'(no method) (0x0000000800088680)
[0.032s][info][class,init] 163 Initializing 'java/lang/ClassCastException'(no method) (0x0000000800085d80)
[0.032s][info][class,init] 164 Initializing 'java/lang/ArrayStoreException'(no method) (0x00000008000859b8)
[0.032s][info][class,init] 165 Initializing 'java/lang/ArithmeticException'(no method) (0x0000000800084b80)
[0.032s][info][class,init] 166 Initializing 'java/lang/StackOverflowError'(no method) (0x000000080008a8b8)
[0.032s][info][class,init] 167 Initializing 'java/lang/IllegalMonitorStateException'(no method) (0x00000008000871f0)
[0.032s][info][class,init] 168 Initializing 'java/lang/IllegalArgumentException'(no method) (0x0000000800086d30)
[0.032s][info][class,init] 169 Initializing 'java/lang/invoke/MethodHandle' (0x00000008000a9fa0)
[0.032s][info][class,init] 170 Initializing 'java/lang/invoke/MethodHandleStatics' (0x00000008000a9a70)
[0.032s][info][class,init] 171 Initializing 'java/lang/Boolean' (0x0000000800030fb8)
[0.032s][info][class,init] 172 Initializing 'java/lang/invoke/ResolvedMethodName'(no method) (0x00000008000c82a8)
[0.032s][info][class,init] 173 Initializing 'java/lang/invoke/MemberName' (0x00000008000c4970)
[0.033s][info][class,init] 174 Initializing 'java/lang/invoke/MethodHandleNatives' (0x00000008000c85a0)
[0.033s][info][class,init] 175 Initializing 'jdk/internal/module/ModuleBootstrap' (0x000000080000db00)
[0.033s][info][class,init] 176 Initializing 'java/lang/invoke/MethodHandles' (0x00000008000b2900)
[0.033s][info][class,init] 177 Initializing 'java/lang/invoke/MemberName$Factory' (0x000000080016f250)
[0.033s][info][class,init] 178 Initializing 'java/lang/invoke/MethodHandles$Lookup' (0x00000008000b4318)
[0.033s][info][class,init] 179 Initializing 'java/lang/StrictMath' (0x000000080008c300)
[0.033s][info][class,init] 180 Initializing 'java/util/ImmutableCollections$MapN$1'(no method) (0x00000008001b6b80)
[0.033s][info][class,init] 181 Initializing 'java/util/ImmutableCollections$MapN$MapNIterator'(no method) (0x00000008001b64e0)
[0.033s][info][class,init] 182 Initializing 'java/util/KeyValueHolder'(no method) (0x000000080015eed8)
[0.033s][info][class,init] 183 Initializing 'sun/invoke/util/VerifyAccess' (0x0000000800171958)
[0.033s][info][class,init] 184 Initializing 'java/lang/reflect/Modifier'(no method) (0x0000000800111a58)
[0.033s][info][class,init] 185 Initializing 'java/lang/module/ModuleDescriptor' (0x0000000800116ca0)
[0.033s][info][class,init] 186 Initializing 'java/lang/module/ModuleDescriptor$1'(no method) (0x00000008001feed0)
[0.033s][info][class,init] 187 Initializing 'java/io/File' (0x000000080006d560)
[0.033s][info][class,init] 188 Initializing 'java/io/DefaultFileSystem'(no method) (0x000000080020a2f0)
[0.034s][info][class,init] 189 Initializing 'java/io/FileSystem' (0x0000000800207978)
[0.034s][info][class,init] 190 Initializing 'java/io/UnixFileSystem' (0x000000080020a598)
[0.034s][info][class,init] 191 Initializing 'java/lang/AbstractStringBuilder' (0x00000008000572d8)
[0.034s][info][class,init] 192 Initializing 'java/lang/StringBuilder'(no method) (0x000000080005c620)
[0.034s][info][class,init] 193 Initializing 'jdk/internal/util/ArraysSupport' (0x0000000800095a20)
[0.034s][info][class,init] 194 Initializing 'jdk/internal/module/ModulePatcher' (0x000000080019acf8)
[0.034s][info][class,init] 195 Initializing 'java/util/HashSet' (0x0000000800100668)
[0.034s][info][class,init] 196 Initializing 'jdk/internal/module/ModuleBootstrap$Counters' (0x00000008001f37a8)
[0.034s][info][class,init] 197 Initializing 'jdk/internal/module/ArchivedBootLayer' (0x00000008001f4058)
[0.034s][info][class,init] 198 Initializing 'java/lang/ModuleLayer' (0x0000000800135690)
[0.034s][info][class,init] 199 Initializing 'java/lang/module/Configuration' (0x0000000800160768)
[0.034s][info][class,init] 200 Initializing 'jdk/internal/loader/AbstractClassLoaderValue' (0x000000080024d958)
[0.034s][info][class,init] 201 Initializing 'jdk/internal/loader/ClassLoaderValue'(no method) (0x000000080024d720)
[0.034s][info][class,init] 202 Initializing 'java/util/ImmutableCollections$List12'(no method) (0x000000080015aa10)
[0.034s][info][class,init] 203 Initializing 'java/lang/module/ResolvedModule'(no method) (0x0000000800161dd8)
[0.034s][info][class,init] 204 Initializing 'java/lang/module/ModuleReference'(no method) (0x00000008001627b0)
[0.034s][info][class,init] 205 Initializing 'jdk/internal/module/ModuleReferenceImpl'(no method) (0x00000008001f6ac8)
[0.034s][info][class,init] 206 Initializing 'java/lang/module/ModuleDescriptor$Version'(no method) (0x000000080015f618)
[0.034s][info][class,init] 207 Initializing 'java/util/ArrayList' (0x00000008000dec90)
[0.034s][info][class,init] 208 Initializing 'java/lang/module/ModuleDescriptor$Requires' (0x0000000800200328)
[0.034s][info][class,init] 209 Initializing 'java/lang/module/ModuleDescriptor$Exports'(no method) (0x0000000800137fd8)
[0.034s][info][class,init] 210 Initializing 'java/lang/module/ModuleDescriptor$Provides'(no method) (0x00000008001ff900)
[0.034s][info][class,init] 211 Initializing 'java/net/URI' (0x0000000800162e58)
[0.034s][info][class,init] 212 Initializing 'java/net/URI$1'(no method) (0x00000008002164e0)
[0.034s][info][class,init] 213 Initializing 'jdk/internal/module/SystemModuleFinders$2'(no method) (0x00000008001f67d0)
[0.034s][info][class,init] 214 Initializing 'jdk/internal/module/SystemModuleFinders$3'(no method) (0x00000008001f70f0)
[0.034s][info][class,init] 215 Initializing 'jdk/internal/module/ModuleTarget'(no method) (0x00000008002114d8)
[0.034s][info][class,init] 216 Initializing 'jdk/internal/module/ModuleHashes'(no method) (0x00000008001f62c8)
[0.034s][info][class,init] 217 Initializing 'java/util/Collections$UnmodifiableMap'(no method) (0x00000008001e68c8)
[0.034s][info][class,init] 218 Initializing 'java/lang/module/ModuleDescriptor$Opens'(no method) (0x0000000800137430)
[0.034s][info][class,init] 219 Initializing 'java/lang/ClassLoader' (0x000000080000e418)
[0.034s][info][class,init] 220 Initializing 'java/security/SecureClassLoader' (0x0000000800066f80)
[0.034s][info][class,init] 221 Initializing 'java/lang/ClassLoader$ParallelLoaders' (0x00000008001265b8)
[0.034s][info][class,init] 222 Initializing 'java/util/WeakHashMap' (0x0000000800122e68)
[0.034s][info][class,init] 223 Initializing 'java/util/Collections$SetFromMap'(no method) (0x00000008001ee308)
[0.034s][info][class,init] 224 Initializing 'java/util/WeakHashMap$KeySet'(no method) (0x0000000800221210)
[0.034s][info][class,init] 225 Initializing 'java/lang/ref/WeakReference'(no method) (0x0000000800047910)
[0.035s][info][class,init] 226 Initializing 'java/util/WeakHashMap$Entry'(no method) (0x0000000800220818)
[0.035s][info][class,init] 227 Initializing 'jdk/internal/loader/BuiltinClassLoader' (0x00000008000816a0)
[0.035s][info][class,init] 228 Initializing 'jdk/internal/loader/ArchivedClassLoaders' (0x00000008000ddba8)
[0.035s][info][class,init] 229 Initializing 'jdk/internal/loader/ClassLoaders$BootClassLoader'(no method) (0x00000008000ddfd8)
[0.035s][info][class,init] 230 Initializing 'java/security/ProtectionDomain' (0x0000000800065d08)
[0.035s][info][class,init] 231 Initializing 'java/security/ProtectionDomain$JavaSecurityAccessImpl'(no method) (0x000000080013a1b8)
[0.035s][info][class,init] 232 Initializing 'java/security/CodeSource'(no method) (0x0000000800064958)
[0.035s][info][class,init] 233 Initializing 'java/security/Principal'(no method) (0x0000000800138e68)
[0.035s][info][class,init] 234 Initializing 'java/security/ProtectionDomain$Key'(no method) (0x0000000800138b80)
[0.035s][info][class,init] 235 Initializing 'jdk/internal/loader/NativeLibraries' (0x000000080007dd78)
[0.035s][info][class,init] 236 Initializing 'jdk/internal/loader/ClassLoaderHelper' (0x0000000800080ec8)
[0.035s][info][class,init] 237 Initializing 'java/util/concurrent/ConcurrentHashMap$CollectionView'(no method) (0x0000000800157490)
[0.035s][info][class,init] 238 Initializing 'java/util/concurrent/ConcurrentHashMap$KeySetView'(no method) (0x00000008001570c0)
[0.035s][info][class,init] 239 Initializing 'jdk/internal/loader/ClassLoaders$PlatformClassLoader' (0x00000008000846a0)
[0.035s][info][class,init] 240 Initializing 'jdk/internal/module/ServicesCatalog' (0x0000000800112fe8)
[0.035s][info][class,init] 241 Initializing 'java/util/concurrent/CopyOnWriteArrayList'(no method) (0x000000080024a7c0)
[0.035s][info][class,init] 242 Initializing 'jdk/internal/module/ServicesCatalog$ServiceProvider'(no method) (0x000000080024d038)
[0.035s][info][class,init] 243 Initializing 'jdk/internal/loader/BuiltinClassLoader$LoadedModule'(no method) (0x0000000800198438)
[0.035s][info][class,init] 244 Initializing 'jdk/internal/loader/ClassLoaders$AppClassLoader' (0x0000000800083e30)
[0.035s][info][class,init] 245 Initializing 'jdk/internal/loader/BootLoader' (0x00000008001126a0)
[0.035s][info][class,init] 246 Initializing 'jdk/internal/loader/ClassLoaders' (0x00000008000dd4c0)
[0.035s][info][class,init] 247 Initializing 'jdk/internal/loader/URLClassPath' (0x00000008000de360)
[0.035s][info][class,init] 248 Initializing 'java/net/URL' (0x0000000800067848)
[0.035s][info][class,init] 249 Initializing 'java/net/URL$DefaultFactory' (0x000000080018d4a8)
[0.035s][info][class,init] 250 Initializing 'java/net/URL$3'(no method) (0x000000080018da88)
[0.035s][info][class,init] 251 Initializing 'java/io/File$PathStatus' (0x00000008002089b8)
[0.035s][info][class,init] 252 Initializing 'sun/net/www/ParseUtil' (0x00000008000785d8)
[0.035s][info][class,init] 253 Initializing 'java/util/HexFormat' (0x0000000800079520)
[0.036s][info][class,init] 254 Initializing 'java/net/URLStreamHandler'(no method) (0x000000080018c1c0)
[0.036s][info][class,init] 255 Initializing 'sun/net/www/protocol/file/Handler'(no method) (0x0000000800228420)
[0.036s][info][class,init] 256 Initializing 'sun/net/util/IPAddressUtil' (0x000000080018a918)
[0.036s][info][class,init] 257 Initializing 'java/util/ArrayDeque'(no method) (0x0000000800221a40)
[0.036s][info][class,init] 258 Initializing 'java/lang/invoke/MethodType' (0x00000008000ab1e8)
[0.036s][info][class,init] 259 Initializing 'java/lang/invoke/MethodType$ConcurrentWeakInternSet'(no method) (0x0000000800182500)
[0.036s][info][class,init] 260 Initializing 'java/lang/Void' (0x00000008000ae890)
[0.036s][info][class,init] 261 Initializing 'java/lang/Long' (0x0000000800040480)
[0.036s][info][class,init] 262 Initializing 'java/lang/invoke/MethodTypeForm' (0x00000008000b08e0)
[0.036s][info][class,init] 263 Initializing 'java/lang/invoke/MethodType$ConcurrentWeakInternSet$WeakEntry'(no method) (0x0000000800182b58)
[0.036s][info][class,init] 264 Initializing 'java/lang/invoke/DirectMethodHandle' (0x00000008000be6f8)
[0.037s][info][class,init] 265 Initializing 'sun/invoke/util/Wrapper' (0x000000080011faa0)
[0.037s][info][class,init] 266 Initializing 'sun/invoke/util/Wrapper$Format' (0x0000000800121148)
[0.037s][info][class,init] 267 Initializing 'java/lang/Short' (0x000000080003bf68)
[0.037s][info][class,init] 268 Initializing 'java/lang/invoke/DirectMethodHandle$Holder'(no method) (0x00000008000d5088)
[0.037s][info][class,init] 269 Initializing 'java/lang/invoke/LambdaMetafactory' (0x0000000800101360)
[0.037s][info][class,init] 270 Initializing 'java/lang/invoke/LambdaForm$Kind' (0x00000008000b2188)
[0.037s][info][class,init] 271 Initializing 'java/lang/invoke/LambdaForm' (0x00000008000af8f0)
[0.037s][info][class,init] 272 Initializing 'java/lang/invoke/LambdaForm$BasicType' (0x00000008000acf88)
[0.037s][info][class,init] 273 Initializing 'java/lang/reflect/Array'(no method) (0x0000000800055378)
[0.037s][info][class,init] 274 Initializing 'java/lang/invoke/LambdaForm$Name' (0x00000008000b0d30)
[0.038s][info][class,init] 275 Initializing 'java/lang/invoke/LambdaForm$Holder'(no method) (0x00000008000d9888)
[0.038s][info][class,init] 276 Initializing 'java/lang/invoke/LambdaForm$NamedFunction' (0x00000008000b1268)
[0.038s][info][class,init] 277 Initializing 'java/lang/invoke/InvokerBytecodeGenerator' (0x0000000800172d00)
[0.038s][info][class,init] 278 Initializing 'java/lang/invoke/InvokerBytecodeGenerator$2' (0x0000000800236640)
[0.038s][info][class,init] 279 Initializing 'java/lang/invoke/MethodHandleImpl$Intrinsic' (0x00000008000b1cd8)
[0.038s][info][class,init] 280 Initializing 'java/lang/ref/SoftReference'(no method) (0x00000008000472a8)
[0.038s][info][class,init] 281 Initializing 'java/lang/invoke/CallSite' (0x00000008000bce48)
[0.038s][info][class,init] 282 Initializing 'java/lang/invoke/BootstrapMethodInvoker' (0x0000000800182ff0)
[0.038s][info][class,init] 283 Initializing 'java/lang/invoke/Invokers' (0x00000008000c9948)
[0.038s][info][class,init] 284 Initializing 'java/lang/invoke/VarHandle$AccessMode' (0x0000000800178908)
[0.039s][info][class,init] 285 Initializing 'java/lang/invoke/VarHandle$AccessType' (0x00000008001795e8)
[0.039s][info][class,init] 286 Initializing 'java/lang/invoke/Invokers$Holder'(no method) (0x00000008000d3b78)
[0.039s][info][class,init] 287 Initializing 'java/lang/invoke/MethodHandleImpl' (0x00000008000a69e8)
[0.039s][info][class,init] 288 Initializing 'java/lang/invoke/MethodHandleImpl$1'(no method) (0x00000008000b4658)
[0.039s][info][class,init] 289 Initializing 'java/lang/invoke/AbstractValidatingLambdaMetafactory'(no method) (0x000000080022cf08)
[0.039s][info][class,init] 290 Initializing 'java/lang/invoke/InnerClassLambdaMetafactory' (0x000000080022ccf8)
[0.039s][info][class,init] 291 Initializing 'jdk/internal/org/objectweb/asm/Type' (0x0000000800205a48)
[0.039s][info][class,init] 292 Initializing 'java/util/concurrent/atomic/AtomicInteger' (0x0000000800185f28)
[0.039s][info][class,init] 293 Initializing 'sun/security/action/GetBooleanAction'(no method) (0x000000080023cb58)
[0.039s][info][class,init] 294 Initializing 'jdk/internal/org/objectweb/asm/Handle'(no method) (0x000000080023d0c8)
[0.039s][info][class,init] 295 Initializing 'sun/invoke/util/BytecodeDescriptor'(no method) (0x0000000800181538)
[0.039s][info][class,init] 296 Initializing 'jdk/internal/org/objectweb/asm/ConstantDynamic'(no method) (0x000000080023d900)
[0.040s][info][class,init] 297 Initializing 'java/lang/invoke/MethodHandleInfo'(no method) (0x00000008001780e0)
[0.040s][info][class,init] 298 Initializing 'java/lang/invoke/InfoFromMemberName' (0x0000000800206b30)
[0.040s][info][class,init] 299 Initializing 'jdk/internal/org/objectweb/asm/ClassVisitor'(no method) (0x0000000800166538)
[0.040s][info][class,init] 300 Initializing 'jdk/internal/org/objectweb/asm/ClassWriter'(no method) (0x0000000800166230)
[0.040s][info][class,init] 301 Initializing 'jdk/internal/org/objectweb/asm/SymbolTable'(no method) (0x000000080023e240)
[0.040s][info][class,init] 302 Initializing 'jdk/internal/org/objectweb/asm/ByteVector'(no method) (0x000000080023feb0)
[0.040s][info][class,init] 303 Initializing 'java/lang/invoke/LambdaProxyClassArchive'(no method) (0x000000080023afe8)
[0.040s][info][class,init] 304 Initializing 'java/util/function/Consumer'(no method) (0x00000008001001a8)
[0.040s][info][class,init] 305 Initializing 'java/util/ArrayDeque$$Lambda$1+0x800000001'(no method) (0x0000000800249d30)
[0.040s][info][class,init] 306 Initializing 'java/lang/invoke/DirectMethodHandle$Constructor' (0x0000000800171178)
[0.040s][info][class,init] 307 Initializing 'java/lang/invoke/ConstantCallSite' (0x00000008000be0b0)
[0.040s][info][class,init] 308 Initializing 'sun/invoke/util/VerifyType'(no method) (0x00000008000aeaa0)
[0.040s][info][class,init] 309 Initializing 'java/lang/invoke/MethodHandleNatives$CallSiteContext'(no method) (0x00000008000cb150)
[0.040s][info][class,init] 310 Initializing 'jdk/internal/ref/CleanerFactory' (0x00000008001856a0)
[0.040s][info][class,init] 311 Initializing 'jdk/internal/ref/CleanerFactory$1'(no method) (0x00000008001859a0)
[0.040s][info][class,init] 312 Initializing 'java/lang/ref/Cleaner' (0x0000000800184208)
[0.040s][info][class,init] 313 Initializing 'java/lang/ref/Cleaner$1'(no method) (0x00000008001851d8)
[0.040s][info][class,init] 314 Initializing 'jdk/internal/ref/CleanerImpl' (0x00000008001845e8)
[0.040s][info][class,init] 315 Initializing 'jdk/internal/ref/PhantomCleanable'(no method) (0x0000000800184af8)
[0.040s][info][class,init] 316 Initializing 'jdk/internal/ref/CleanerImpl$PhantomCleanableRef'(no method) (0x0000000800184888)
[0.040s][info][class,init] 317 Initializing 'jdk/internal/ref/CleanerImpl$CleanerCleanable'(no method) (0x000000080024a400)
[0.040s][info][class,init] 318 Initializing 'jdk/internal/misc/InnocuousThread' (0x000000080014d9d0)
[0.041s][info][class,init] 319 Initializing 'java/util/concurrent/TimeUnit' (0x000000080013f2e8)
[0.041s][info][class,init] 320 Initializing 'java/util/concurrent/locks/AbstractQueuedSynchronizer$Node' (0x00000008001d5400)
[0.041s][info][class,init] 321 Initializing 'java/util/concurrent/locks/AbstractQueuedSynchronizer$ConditionNode'(no method) (0x00000008001d5b38)
[0.041s][info][class,init] 322 Initializing 'java/util/concurrent/locks/LockSupport' (0x00000008001a89d8)
[0.041s][info][class,init] 323 Initializing 'java/lang/invoke/StringConcatFactory' (0x000000080000e0e8)
[0.041s][info][class,init] 324 Initializing 'java/lang/invoke/StringConcatFactory$1'(no method) (0x0000000800252790)
[0.041s][info][class,init] 325 Initializing 'java/lang/invoke/StringConcatFactory$2'(no method) (0x0000000800252cd0)
[0.041s][info][class,init] 326 Initializing 'java/lang/invoke/StringConcatFactory$3'(no method) (0x00000008002531a8)
[0.042s][info][class,init] 327 Initializing 'java/nio/CharBuffer' (0x00000008000e7330)
[0.042s][info][class,init] 328 Initializing 'java/nio/HeapCharBuffer' (0x0000000800278290)
[0.042s][info][class,init] 329 Initializing 'java/lang/StringCoding'(no method) (0x000000080008f4c0)
[0.042s][info][class,init] 330 Initializing 'java/lang/Shutdown' (0x00000008000457e0)
[0.042s][info][class,init] 331 Initializing 'java/lang/Shutdown$Lock'(no method) (0x00000008002575c8)

Оказывается, что появление ссылки на метод требует загрузки 65 (!) дополнительных классов и время загрузки возрастает с 0,038 до 0,042 секунд (Intel Core i7, LPDDR4X, SSD).

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

Аналогичные предупреждения прописаны в коде методов BuiltinClassLoader.findClassOnClassPathOrNull() и BuiltinClassLoader.moduleReaderFor() (ссыль1 и ссыль2).

Вывод из этой истории созвучен со сделанным мной в первой части повествования (раздел "Нюансы исполнения"): даже для очень простых и алгоритмически выверенных улучшений очень важен контекст.

Склеивание строк

Однажды во время отладки своего приложения я провалился внутрь Class.getResource() и обнаружил в нём обращение к Class.resolveName() с прекрасным кодом:

private String resolveName(String name) {
  if (!name.startsWith("/")) {
    String baseName = getPackageName();
    if (!baseName.isEmpty()) {
      int len = baseName.length() + 1 + name.length();
      StringBuilder sb = new StringBuilder(len);
      name = sb.append(baseName.replace('.', '/'))
          .append('/')
          .append(name)
          .toString();
    }
  } else {
    name = name.substring(1);
  }
  return name;
}

Разумеется, я не мог пройти мимо такой вкусняшки :)

Ну серьёзно, 2022 год на дворе, а тут до сих пор для складывания трёх строк используется StringBuilder, непорядок. Очевидно же, что можно сделать короче и лучше:

private String resolveName(String name) {
  if (!name.startsWith("/")) {
    String baseName = getPackageName();
    if (!baseName.isEmpty()) {
      name = baseName.replace('.', '/') + '/' + name;
    }
  } else {
    name = name.substring(1);
  }
  return name;
}

Когда код был переписан встал вопрос о проверке. Поскольку метод приватный и вызвать его извне j.l.Class нельзя (даже с помощью рефлексии — гайки там закручены туго), я решил эту задачу изящным (как мне казалось) способом:

@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"})
public class ResolveNameBenchmark {

  private final Class<? extends ResolveNameBenchmark> klazz = getClass();

  @Benchmark
  public Object original() {
    return original("com/tsypanov/ovn/ResolveNameBenchmark.class");
  }

  @Benchmark
  public Object patched() {
    return patched("com/tsypanov/ovn/ResolveNameBenchmark.class");
  }

  private String original(String name) {
    if (!name.startsWith("/")) {
      String baseName = getPackageName();
      if (!baseName.isEmpty()) {
        int len = baseName.length() + 1 + name.length();
        StringBuilder sb = new StringBuilder(len);
        name = sb.append(baseName.replace('.', '/'))
                .append('/')
                .append(name)
                .toString();
      }
    } else {
      name = name.substring(1);
    }
    return name;
  }

  private String patched(String name) {
    if (!name.startsWith("/")) {
      String baseName = getPackageName();
      if (!baseName.isEmpty()) {
        return baseName.replace('.', '/') + '/' + name;
      }
      return name;
    }
    return name.substring(1);
  }

  private String getPackageName() {
    return klazz.getPackageName();
  }
}

Здесь всё логично: мы не можем вызвать нужный метод напрямую, но можем воспроизвести его, вызывая доступный извне getPackageName(). Прогон показал ощутимый прирост даже для короткой строки:

                                            Mode  Cnt     Score     Error   Units

original                                    avgt   50    57.974 ±   0.365   ns/op
original:·gc.alloc.rate                     avgt   50  3419.447 ±  21.154  MB/sec
original:·gc.alloc.rate.norm                avgt   50   312.006 ±   0.001    B/op
original:·gc.churn.G1_Eden_Space            avgt   50  3399.396 ± 149.836  MB/sec
original:·gc.churn.G1_Eden_Space.norm       avgt   50   310.198 ±  13.628    B/op
original:·gc.churn.G1_Survivor_Space        avgt   50     0.004 ±   0.001  MB/sec
original:·gc.churn.G1_Survivor_Space.norm   avgt   50    ≈ 10⁻³              B/op
original:·gc.count                          avgt   50   208.000            counts
original:·gc.time                           avgt   50   224.000                ms

patched                                     avgt   50    44.367 ±   0.162   ns/op
patched:·gc.alloc.rate                      avgt   50  2749.265 ±  10.014  MB/sec
patched:·gc.alloc.rate.norm                 avgt   50   192.004 ±   0.001    B/op
patched:·gc.churn.G1_Eden_Space             avgt   50  2729.221 ± 193.552  MB/sec
patched:·gc.churn.G1_Eden_Space.norm        avgt   50   190.615 ±  13.539    B/op
patched:·gc.churn.G1_Survivor_Space         avgt   50     0.003 ±   0.001  MB/sec
patched:·gc.churn.G1_Survivor_Space.norm    avgt   50    ≈ 10⁻⁴              B/op
patched:·gc.count                           avgt   50   167.000            counts
patched:·gc.time                            avgt   50   181.000                ms

Сразу же был оформлен ПР, в комментариях к которому вкрадчиво спросили "а там точно есть прирост?" Произошёл примерно такой разговор:

- Вот изменения, дающий отличный результат!

- А он там точно есть?

- Ну да, я вот и бенчмарк написал!

- Он меряет не то, что было изменено.

- Код-то один и тот же. Разве может быть разница?

- А ты перепроверь и узнаешь ????.

Ввиду зародившихся сомнений встал вопрос: а как именно измерить производительность метода, который приватный и к которому модульный JDK никак не даёт достучаться?

Первое, что я сделал, — объявил метод публичным и пересобрал JDK. Не тут то было! Компилятор всё равно ругался, мол, 'resolveName' has private access in 'java.lang.Class' (хотя редактор "Идеи" клялся, что ошибки нет). Выяснилось, что нужно изменить также один из файлов с расширением *.sym.txt, в котором содержаться публичные методы, ставшие доступными в разных версиях JDK. В моём случае это был jdk/src/jdk.compiler/share/data/symbols/java.base-H.sym.txt (здесь jdk/ — корневая папка исходников):

class name java/lang/Class
-method name isSealed descriptor ()Z
-method name getPermittedSubclasses descriptor ()[Ljava/lang/Class;
method name getPermittedSubclasses descriptor ()[Ljava/lang/Class; flags 1 signature ()[Ljava/lang/Class<*>; runtimeAnnotations @Ljdk/internal/reflect/CallerSensitive;
method name isSealed descriptor ()Z flags 1

в который после строчки с -method name getPermittedSubclasses я дописал

-method name resolveName descriptor (Ljava/lang/String)Ljava/lang/String; flags 1

Теперь правильный бенчмарк выглядит вот так:

@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"})
public class GetResourceBenchmark {
  private final Class<?> klazz = getClass();

  @Benchmark
  public String resolveName() {
    return klazz.resolveName("com/tsypanov/ovn/GetResourceBenchmark.class");
  }
}

И предложенные изменения (StringBuilder -> +) не улучшают, а ухудшают производительность:

до
                                              Mode  Cnt     Score     Error   Units
resolveName                                   avgt   50    51,487 ±   3,357   ns/op
resolveName:·gc.alloc.rate                    avgt   50  4680,362 ± 241,137  MB/sec
resolveName:·gc.alloc.rate.norm               avgt   50   312,006 ±   0,001    B/op
resolveName:·gc.churn.G1_Eden_Space           avgt   50  4698,863 ± 258,117  MB/sec
resolveName:·gc.churn.G1_Eden_Space.norm      avgt   50   313,425 ±   7,379    B/op
resolveName:·gc.churn.G1_Survivor_Space       avgt   50     0,004 ±   0,001  MB/sec
resolveName:·gc.churn.G1_Survivor_Space.norm  avgt   50    ≈ 10⁻⁴              B/op
resolveName:·gc.count                         avgt   50   480,000            counts
resolveName:·gc.time                          avgt   50   757,000                ms

после
                                              Mode  Cnt     Score     Error   Units
resolveName                                   avgt   50    72,647 ±   3,354   ns/op
resolveName:·gc.alloc.rate                    avgt   50  4228,087 ± 178,777  MB/sec
resolveName:·gc.alloc.rate.norm               avgt   50   400,008 ±   0,001    B/op
resolveName:·gc.churn.G1_Eden_Space           avgt   50  4217,788 ± 200,576  MB/sec
resolveName:·gc.churn.G1_Eden_Space.norm      avgt   50   399,001 ±   8,514    B/op
resolveName:·gc.churn.G1_Survivor_Space       avgt   50     0,003 ±   0,001  MB/sec
resolveName:·gc.churn.G1_Survivor_Space.norm  avgt   50    ≈ 10⁻³              B/op
resolveName:·gc.count                         avgt   50   431,000            counts
resolveName:·gc.time                          avgt   50   678,000                ms

И да, если бы я не умничал, а с самого начала посмотрел историю метода resolveName(), то увидел бы там это:

Внезапно

Обычно в таких ситуациях ораклоиды смотрят на тебя примерно вот так:

????

Получается, один и тот же код (очень простой и состоящий из базовых частей стандартной библиотеки) ведёт себя по-разному внутри JDK и за его пределами. Но даже не это удивило больше всего. В высшей степени неочевидно, что склеивание строк через "+" в JDK работает медленнее, чем за его пределами.

Это вдвойне странно просто потому, что там внутри есть много "ускорителей", недоступных простым смертным:

  • Unsafe.allocateUninitializedArray(Class, int)

  • Class.getInterfaces(boolean)

  • StringLatin1.getChar(int)

  • String.newStringNoRepl(byte[], Charset)

  • @Stable

Unsafe.allocateUninitializedArray позволяет создать массив минуя требуемое спецификацией принудительное зануление всех его ячеек, что даёт выигрыш при полном заполнении массива свежими данными.

Class.getInterfaces(false) возвращает массив интерфейсов без выделения памяти, StringLatin1.getChar(int) вместо String.charAt(int) не делает проверку выхода за границы строки, а String.newStringNoRepl(byte[], Charset) создаёт строку без копирования входящего массива, что удобно и безопасно при условии его неутекания за пределы метода. @Stable — это аннотация ускоряющая доступ к помеченным объектам и их содержимому.

Логично предположить, что код внутри java.lang.Class будет быстрее. Увы, обычная логика внутри JDK работает не всегда.

Итак, часть нашего кода, соединяющая строки через "+"

return baseName.replace('.', '/') + '/' + name;

при сборке превращается в

INVOKEVIRTUAL java/lang/String.replace (CC)Ljava/lang/String;
ALOAD 1
INVOKEDYNAMIC makeConcatWithConstants(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; [
  // handle kind 0x6 : INVOKESTATIC
  java/lang/invoke/StringConcatFactory.makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
  // arguments:
  "\u0001/\u0001"
]
ARETURN

Этот же код внутри JDK компилируется так:

 INVOKESPECIAL java/lang/StringBuilder.<init> (I)V
 ASTORE 4
L7
 LINENUMBER 3182 L7
 ALOAD 4
 ALOAD 2
 BIPUSH 46
 BIPUSH 47
 INVOKEVIRTUAL java/lang/String.replace (CC)Ljava/lang/String;
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 BIPUSH 47
L8
 LINENUMBER 3183 L8
 INVOKEVIRTUAL java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;
 ALOAD 1
L9
 LINENUMBER 3184 L9
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
L10
 LINENUMBER 3185 L10
 INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;

Получается, для javac существует разница между кодом j.l.Class и пользовательским кодом. Понять причину этого поможет уже знакомая нам команда: java -Xlog:class+init -version.

Дело в том, что StringConcatFactory недоступен на ранних стадиях запуска приложения из-за циклических зависимостей, поэтому любое соединение строк внутри модуля java.base превращается в хорошо знакомую по старым версиям Java цепочку new StringBuilder().append().toString(), при этом сколько бы метод не вызывался в дальнейшем, он уже не оптимизируется.

Эта неочевидность имеет несколько любопытных следствий:

  • правило замены цепочки new StringBuilder().append().toString() сложением, которое нам вдалбливали как кол в печень, переворачивается на 180 градусов! В отличие от клиентского кода, внутри JDK оно ухудшает производительность;

  • внутри java.base на горячих участках склеивание через "+" нужно заменять той самой устаревшей цепочкой new StringBuilder().append().toString(), по возможности передавая длину итоговой строки в конструктор;

  • второе дыхание открывается у метода String.concat().

С первым и вторым пунктами всё понятно: бери и делай.

Третий интереснее: метод String.concat() почти не используется (особенно после JDK-8222484 и JDK-8247605, про что подробно рассказано в докладе "Ещё немного маленьких оптимизаций"), т. к. в пользовательском коде он стал бессмысленным. А вот в коде JDK благодаря своему хитрому устройству

public String concat(String str) {
  if (str.isEmpty()) {
    return this;
  }
  return StringConcatHelper.simpleConcat(this, str);
}

он обретает вторую жизнь, позволяя увернуться от new StringBuilder().append() при сложении двух строк и давая ощутимые приросты. Также он хорошо ложится в сценарий склеивания трёх строк, одна из которых может оказаться пустой и исключаемой из цепочки.

Несколько иначе ведёт себя и привычный String.valueOf().

В уже упомянутом "Катехизисе java.lang.String" было показано сравнение "" + i и String.valueOf(i) и тогда (в 2015 году) склеивание работало быстрее из-за хорошо оптимизированного StringBuilder.append(int). Но это было до того, как у нас появился StringConcatFactory. С ним "" + i в конце-концов превращается в эквивалент String.valueOf(i), но уже внутри StringConcatHelper:

static String simpleConcat(Object first, Object second) {
  String s1 = stringOf(first);
  String s2 = stringOf(second);
  // ...
}

static String stringOf(Object value) {
  String s;
  return (value == null || (s = value.toString()) == null) ? "null" : s;
}

Поэтому если мы берём бенчмарк из упомянутого доклада

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"})
public class ValueOfBenchmark {
    @Benchmark
    public String concat(Data data) {
        return "" + data.value;
    }

    @Benchmark
    public String valueOf(Data data) {
        return String.valueOf(data.value);
    }

    @State(Scope.Thread)
    public static class Data {
        int value = 12345;
    }
}

то оказывается, что для постоянного значения цифры примерно те же:

Java 11

Benchmark                Mode  Cnt     Score     Error   Units
ValueOfBenchmark.concat  avgt   40     6,668 ±   0,740   ns/op
ValueOfBenchmark.valueOf avgt   40     6,536 ±   0,110   ns/op

Однако в бенчмарке со случайным объектом:

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"})
public class ValueOfBenchmark {

  @Benchmark
  public String concat(Data data) {
    return "" + data.value;
  }

  @Benchmark
  public String valueOf(Data data) {
    return String.valueOf(data.value);
  }

  @State(Scope.Thread)
  public static class Data {
    Object value = new Object(){
      @Override
      public int hashCode() {
        return 42; // постоянная для стабильности, см. Object.toString()
      }
    };
  }
}

"+" начинает ощутимо проигрывать:

Java 11

Benchmark                 Mode  Cnt   Score   Error  Units
ValueOfBenchmark.concat   avgt   40  54,070 ± 3,225  ns/op
ValueOfBenchmark.valueOf  avgt   40  43,012 ± 2,408  ns/op

В Java 17 показатели почти сравниваются:

Java 17

Benchmark                 Mode  Cnt   Score   Error  Units
ValueOfBenchmark.concat   avgt   40  41,501 ± 0,806  ns/op
ValueOfBenchmark.valueOf  avgt   40  39,194 ± 2,441  ns/op

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

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

Видите, казалось бы сложение строк: что может быть проще, вопрос 100 раз раскрыт, а сколько здесь нюансов и тонких угловых случаев.

На сегодня всё. Присылайте ваши примеры неочевидного кода в комментарии, будем разбирать :)

До новых встреч!

Комментарии (4)


  1. Cdracm
    20.07.2022 18:53
    +1

    Жестко, спасибо. Дык то есть внутри JDK бутстрапа "a"+"b" компилируется в `new StringBuilder().append("a").append("b")` и это медленнее чем переписывание вручную на `new StringBuilder(2).append("a").append("b")` ? И почему вы тогда не хотите, вместо переписывания всех внутренностей JDK на StringBuilder(length), пофиксить этот баг с неоптимальной компиляцией плюса? Шобы если "a"+"b" компилируется в StringBuilder а не в invokeDynamic, он бы уж компилировался в StringBuilder c правильным length?


    1. tsypanov Автор
      20.07.2022 23:30

      Точно не знаю, вероятно, из-за возможных НПЕ в коде вроде:

      int length = str1.length() + str2.length();
      new StringBuilder().append(str1).append(str2).toString();

      Было предложение заменять сложение строго двух строк явным вызовом str1.concat(str2), но тут во-первых нарушается требование спецификации о создании новой строки при сложении, во-вторых возможен НПЕ.


  1. quaer
    21.07.2022 01:41

    Это зависит от ОС, версии ява-машины, типа процессора? На Андроиде, например, такие же результаты будут?


    1. tsypanov Автор
      21.07.2022 10:45

      Абсолютные числа, разумеется, зависят от процессора и версии JDK, в статье я как раз и привёл пример кода, который работает по-разному в зависимости от версии явы.

      От оси соотношения между показателями по идее не должны зависеть (как и абсолютные значения).

      Про Андроид точно сказать не могу, я никогда не разрабатывал под мобильные устройства. Если JDK и JRE там те же, что и на настольных машинах, то всё будет так же.