【问题标题】:Why JIT compiles some methods at the startup?为什么 JIT 在启动时会编译一些方法?
【发布时间】:2019-04-24 09:19:50
【问题描述】:

我正在研究一个非常简单的代码块的 JIT 行为:

public class PlayWithAssembly {

    public static void main(String[] args) {
        Random random = new Random();
        random.nextInt();
    }
}

实际上,就我的问题而言,main 方法的内容完全无关紧要。我在 Ubuntu 16.04.5 上使用 OpenJDK 10.0.1 并使用以下命令运行以下代码 java -Xbatch -XX:+PrintCompilation -XX:CompileThreshold=1000000 -cp target/classes com.xxx.playground.internal.bytecode.PlayWithAssembly

由于CompileThreshold 设置为非常高的值,我不希望 JIT 编译任何东西,我宁愿希望 JVM 在此示例的实践中完全以解释模式运行。但是在运行上述命令时,我得到了一个已编译的方法列表(它们都是 JDK 的一部分):

 47    1    b  3       java.lang.StringLatin1::hashCode (42 bytes)
 50    2    b  3       java.util.concurrent.ConcurrentHashMap::tabAt (22 bytes)
 51    3     n 0       jdk.internal.misc.Unsafe::getObjectVolatile (native)   
 55    4    b  3       java.lang.Object::<init> (1 bytes)
 56    5    b  3       java.lang.String::isLatin1 (19 bytes)
 56    6    b  3       java.lang.String::hashCode (49 bytes)
 57    7    b  3       java.lang.String::coder (15 bytes)
 58    8    b  3       java.lang.Math::floorMod (10 bytes)
 59    9    b  3       java.util.ImmutableCollections$SetN::probe (60 bytes)
 62   10    b  1       java.util.ImmutableCollections$Set0::hashCode (2 bytes)
 62   11    b  3       java.lang.String::equals (65 bytes)
 64   12    b  1       java.util.Collections$EmptySet::hashCode (2 bytes)
 65   13    b  3       java.lang.StringLatin1::equals (36 bytes)
 66   14    b  3       java.util.Collections::emptySet (4 bytes)
 66   15    b  3       java.lang.module.ModuleDescriptor$Exports::<init> (10 bytes)
 67   16    b  4       java.lang.StringLatin1::hashCode (42 bytes)
 71    1       3       java.lang.StringLatin1::hashCode (42 bytes)   made not entrant
 72   17    b  3       java.lang.module.ModuleDescriptor$Exports::hashCode (38 bytes)
 73   18    b  3       java.util.Objects::equals (23 bytes)
 73   19    b  3       java.util.Objects::requireNonNull (14 bytes)
 74   20    b  3       java.util.AbstractCollection::<init> (5 bytes)
 76   21    b  3       java.util.AbstractSet::<init> (5 bytes)
 76   22    b  3       java.util.ImmutableCollections$AbstractImmutableSet::<init> (5 bytes)
 77   23    b  1       java.lang.Object::<init> (1 bytes)
 77    4       3       java.lang.Object::<init> (1 bytes)   made not entrant
 81   24    b  1       java.lang.module.ModuleDescriptor::name (5 bytes)
 82   25    b  1       java.lang.module.ModuleReference::descriptor (5 bytes)
 88   26    b  3       java.lang.String::charAt (25 bytes)
 93   27    b  3       java.util.concurrent.ConcurrentHashMap::spread (10 bytes)
 94   28    b  3       java.util.ImmutableCollections$SetN$1::hasNext (47 bytes)
 95   29    b  3       java.util.ImmutableCollections$SetN$1::next (35 bytes)
 96   30    b  3       java.util.Set::of (66 bytes)
 98   31    b  1       java.util.KeyValueHolder::getKey (5 bytes)
 99   32    b  1       java.util.KeyValueHolder::getValue (5 bytes)
100   33    b  3       java.util.ImmutableCollections$MapN::probe (64 bytes)
101   34    b  3       java.util.KeyValueHolder::<init> (21 bytes)
102   35    b  3       java.util.ImmutableCollections$MapN::get (21 bytes)
103   36     n 0       java.lang.Object::hashCode (native)   
103   37    b  3       jdk.internal.module.ModuleReferenceImpl::hashCode (56 bytes)
105   38    b  3       java.util.HashMap::hash (20 bytes)
106   39   !b  3       java.util.concurrent.ConcurrentHashMap::putVal (432 bytes)
112   40     n 0       jdk.internal.misc.Unsafe::compareAndSetLong (native)   
112   41    b  3       java.util.concurrent.ConcurrentHashMap::putIfAbsent (8 bytes)
112   42    b  1       java.lang.module.ResolvedModule::reference (5 bytes)
113   43    b  3       java.util.concurrent.ConcurrentHashMap::addCount (289 bytes)
115    2       3       java.util.concurrent.ConcurrentHashMap::tabAt (22 bytes)   made not entrant
115   39   !   3       java.util.concurrent.ConcurrentHashMap::putVal (432 bytes)   made not entrant
115   44    b  3       jdk.internal.misc.Unsafe::getObjectAcquire (7 bytes)
116   45    b  3       java.util.concurrent.ConcurrentHashMap::tabAt (22 bytes)
116   46     n 0       jdk.internal.misc.Unsafe::compareAndSetObject (native)   
117   47    b  3       java.util.concurrent.ConcurrentHashMap$Node::<init> (20 bytes)
117   48   !b  3       java.util.concurrent.ConcurrentHashMap::putVal (432 bytes)
120   49    b  3       java.util.concurrent.ConcurrentHashMap::casTabAt (21 bytes)
122   50    b  3       java.util.HashMap::getNode (148 bytes)
124   51    b  3       java.lang.String::length (11 bytes)
125   52    b  3       java.lang.StringLatin1::canEncode (13 bytes)
126   53    b  3       java.util.HashMap::put (13 bytes)
127   54     n 0       java.lang.System::arraycopy (native)   (static)
128   55    b  3       java.util.HashMap$Node::<init> (26 bytes)
128   56    b  3       java.util.HashMap::newNode (13 bytes)
129   57    b  3       java.util.HashMap::afterNodeInsertion (1 bytes)
129   58    b  3       java.util.Optional::ofNullable (15 bytes)
131   59    b  3       java.util.HashMap::get (23 bytes)
132   60    b  3       java.util.HashMap::putVal (300 bytes)
135   61    b  1       java.lang.module.ModuleDescriptor$Exports::source (5 bytes)
135   62    b  1       java.util.Collections$1::hasNext (5 bytes)
136   63    b  3       java.lang.module.ResolvedModule::name (11 bytes)
137   64    b  3       java.util.HashSet::add (20 bytes)
137   65    b  1       java.util.Collections$EmptySet::isEmpty (2 bytes)
138   66    b  3       java.lang.module.ResolvedModule::hashCode (16 bytes)
139   67    b  3       java.lang.module.ModuleDescriptor$Exports::isQualified (18 bytes)
140   68    b  1       java.lang.module.ModuleDescriptor::isAutomatic (5 bytes)
140   69    b  3       java.util.AbstractMap::<init> (5 bytes)
141   70    b  1       java.lang.module.ModuleDescriptor$Exports::targets (5 bytes)
141   71    b  1       java.lang.module.ResolvedModule::configuration (5 bytes)
142   72    b  3       java.util.HashMap::<init> (11 bytes)
142   73    b  3       java.util.ImmutableCollections$Set2$1::hasNext (14 bytes)
143   74    b  4       java.util.ImmutableCollections$SetN$1::hasNext (47 bytes)
148   28       3       java.util.ImmutableCollections$SetN$1::hasNext (47 bytes)   made not entrant
149   75    b  1       java.util.ImmutableCollections$Set1::size (2 bytes)
150   76    b  3       java.lang.Math::min (11 bytes)
152   77    b  3       java.util.AbstractCollection::isEmpty (13 bytes)
153   78    b  4       java.lang.String::hashCode (49 bytes)
160    6       3       java.lang.String::hashCode (49 bytes)   made not entrant
162   79    b  3       java.util.Map::entry (10 bytes)
165   80    b  1       java.lang.module.ModuleDescriptor::isOpen (5 bytes)
167   81    b  1       java.util.HashMap::afterNodeInsertion (1 bytes)
167   57       3       java.util.HashMap::afterNodeInsertion (1 bytes)   made not entrant
168   82    b  3       jdk.internal.module.ModuleBootstrap$2::hasNext (30 bytes)
169   83    b  3       java.util.HashMap::resize (356 bytes)
171   84    b  3       java.util.Collections$UnmodifiableCollection$1::hasNext (10 bytes)
172   85    b  3       jdk.internal.module.ModuleBootstrap$2::next (52 bytes)
173   86    b  3       java.util.HashMap::putIfAbsent (13 bytes)
174   87     n 0       java.lang.Module::addExportsToAllUnnamed0 (native)   (static)
175   88    b  1       java.lang.Module::getDescriptor (5 bytes)
182   78       4       java.lang.String::hashCode (49 bytes)   made not entrant
185   89    b  3       java.lang.StringLatin1::indexOf (61 bytes)
187   23       1       java.lang.Object::<init> (1 bytes)   made not entrant
195   90    b  1       java.lang.Object::<init> (1 bytes)
197   91    b  3       java.lang.String::hashCode (49 bytes) 

我试图将这些方法与内在函数列表匹配,但它不匹配,所以我的问题是:为什么这些方法被编译(而其他方法没有),我可以控制它吗?

【问题讨论】:

  • JVM 在启动过程中进行了大量处理,这些方法被调用了超过 10,000 次(或循环 10,000 次)。第一次使用(或之前)触发编译方法没有什么好处
  • @PeterLawrey 是的,我完全了解与立即编译该方法相关的权衡。我将CompileThreshold 设置为1 对其进行了测试,代码运行时间超过4 秒(启用了后台编译)。您是否有任何起点来挖掘 JVM 正在做什么来运行我的 main 方法?

标签: java optimization jvm jit


【解决方案1】:

来自the documentation of -XX:CompileThreshold

启用分层编译时忽略此选项;
查看选项-XX:-TieredCompilation

因此,当指定-XX:-TieredCompilation 时,这些条目中的大部分将消失,但是,某些条目可能仍不受基于计数器的编译决策的影响。

【讨论】:

  • 注意:从 JIT 的角度来看,在调用 main() 之前调用和编译的代码并没有什么特别之处。 I它们的编译原因与调用 main() 后的代码编译 +1
  • 就是这样!我加了-XX:-TieredCompilation,现在感觉真的控制了门槛。现在引起我注意的是,即使在将CompileThreshold 设置为40000 之后,方法java.lang.StringLatin1::hashCode 仍然可以编译!这意味着甚至在运行main() 方法之前就已经发生了很多围绕字符串计算哈希码的事情!实际上对于我的环境,这正是 45955 调用。
  • @MateuszPrzybyla 好吧,哈希字符串一直在发生。想想系统属性(不仅是那些存在的,每个查询的键也需要散列),所有加载的类,语言环境数据,文件系统缓存等。我不知道,也许,即使是字符串实习也求助于 Java 端散列代码实现。不太可能在启动时发生,但即使是垃圾收集器也可能在激活重复数据删除时散列字符串……
猜你喜欢
  • 1970-01-01
  • 2023-03-29
  • 2010-10-16
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 2011-03-31
  • 2020-06-20
  • 2018-06-09
相关资源
最近更新 更多