- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在Windows上使用AdoptJDk 11.0.7 Java,并启用了-XX:+ PrintCompilation标志,因此我可以看到正在编译的方法,而只是解释了
我正在应用程序中调用某些功能(该功能处理音频文件并在文件上创建html报告)。我启动了应用程序一次(虽然GUI有限),然后在同一组文件上运行相同任务多次。第二次调用它的运行速度比第一次快得多,第三次比第二次要快一些,因此后续运行之间没有太大差异。但是我注意到,每次运行时,它仍在编译许多方法,并且许多方法变得不可重入。
它是分层编译的,所以我知道可以将同一方法重新编译到更高的级别,但是正在编译的方法数量似乎并没有太大变化。
我不明白为什么这么多方法变成不可重入的(然后是僵尸),我还没有做详细的分析,但是似乎一遍又一遍地编译了相同的方法,为什么呢?
我添加了-XX:-BackgroundCompilation
选项,以强制按顺序编译方法,并使代码等待编译版本,而不是在编译时使用解释版本。这似乎减少了可重入方法的数量,也许这是因为它减少了多个线程尝试访问(重新)编译的方法的机会?
但是仍然有很多方法可以重新编译
例如,在这里我可以看到它被编译为3级,然后被编译为4级,因此3级编译成为不可进入的且僵化了。但是随后第4级变得不可重入,然后又回到第4级进行编译,依此类推。
最佳答案
简短的答案是,JIT取消优化会导致禁用已编译的代码(“不让其进入”),释放该代码(“使不让僵尸”)并在再次调用时重新编译(足够的次数)。
JVM方法高速缓存维护四个状态:
enum {
in_use = 0, // executable nmethod
not_entrant = 1, // marked for deoptimization but activations
// may still exist, will be transformed to zombie
// when all activations are gone
zombie = 2, // no activations exist, nmethod is ready for purge
unloaded = 3 // there should be no activations, should not be
// called, will be transformed to zombie immediately
};
in_use
,它可能已被取消优化禁用(
not_entrant
),但仍可以调用,或者可以将其标记为
zombie
,如果它是
non_entrant
且不再使用。最后,可以将该方法标记为要卸载。
-XX:+PrintCompilation
输出中的编译级别范围从
0
到
4
。
0
代表解释,
1
到
3
代表客户端编译器的不同优化级别,
4
代表服务器编译器。在输出中,您可以看到
java.lang.String.equals()
从
3
过渡到
4
。发生这种情况时,原始方法将标记为
not_entrant
。仍然可以调用它,但是一旦不再引用它,它将转换为
zombie
。
hotspot/share/runtime/sweeper.cpp
)是一项后台任务,负责管理方法生命周期并将
not_reentrant
方法标记为
zombie
。扫描间隔取决于许多因素,一个是方法缓存的可用容量。低容量将增加背景扫描的次数。您可以使用
-XX:+PrintMethodFlushing
监视清除 Activity (仅JVM调试版本)。可以通过最小化缓存大小并最大化其攻击性阈值来提高扫描频率:
-XX:StartAggressiveSweepingAt=100 (JVM debug builds only)
-XX:InitialCodeCacheSize=4096 (JVM debug builds only)
-XX:ReservedCodeCacheSize=3m (JVM debug builds noly)
-XX:MinPassesBeforeFlush=0
(仅JVM调试版本)设置为强制立即转换。
while (true) {
String x = new String();
}
517 11 b 3 java.lang.String::<init> (12 bytes)
520 11 3 java.lang.String::<init> (12 bytes) made not entrant
520 12 b 4 java.lang.String::<init> (12 bytes)
525 12 4 java.lang.String::<init> (12 bytes) made not entrant
533 11 3 java.lang.String::<init> (12 bytes) made zombie
533 12 4 java.lang.String::<init> (12 bytes) made zombie
533 15 b 4 java.lang.String::<init> (12 bytes)
543 15 4 java.lang.String::<init> (12 bytes) made not entrant
543 13 4 java.lang.String::<init> (12 bytes) made zombie
java.lang.String
的构造函数先用C1编译,然后用C2编译。 C1的结果被标记为
not_entrant
和
zombie
。后来,对于C2结果也是如此,此后将进行新的编译。
zombie
状态都将触发新的编译。因此,这可能会反复发生。取决于主要因素,
zombie
状态可能会延迟(根据您的情况),具体取决于已编译代码的年龄(通过
-XX:MinPassesBeforeFlush
控制),方法缓存的大小和可用容量以及
not_entrant
方法的使用。
in_use
->
not_entrant
->
zombie
->
in_use
)。但是,除了从C1过渡到C2之外,什么还可以触发
not_entrant
,方法使用期限约束和方法缓存大小矛盾,以及如何可视化推理?
-XX:+TraceDeoptimization
(仅JVM调试版本),您可以了解将给定方法标记为
not_entrant
的原因。在上述示例的情况下,输出为(为便于阅读而缩短/重新格式化):
Uncommon trap occurred in java.lang.String::<init>
reason=tenured
action=make_not_entrant
-XX:MinPassesBeforeFlush=0
施加了年龄限制:
Reason_tenured, // age of the code has reached the limit
Reason_null_check, // saw unexpected null or zero divisor (@bci)
Reason_null_assert, // saw unexpected non-null or non-zero (@bci)
Reason_range_check, // saw unexpected array index (@bci)
Reason_class_check, // saw unexpected object class (@bci)
Reason_array_check, // saw unexpected array class (aastore @bci)
Reason_intrinsic, // saw unexpected operand to intrinsic (@bci)
Reason_bimorphic, // saw unexpected object class in bimorphic
Reason_profile_predicate, // compiler generated predicate moved from
// frequent branch in a loop failed
Reason_unloaded, // unloaded class or constant pool entry
Reason_uninitialized, // bad class state (uninitialized)
Reason_unreached, // code is not reached, compiler
Reason_unhandled, // arbitrary compiler limitation
Reason_constraint, // arbitrary runtime constraint violated
Reason_div0_check, // a null_check due to division by zero
Reason_age, // nmethod too old; tier threshold reached
Reason_predicate, // compiler generated predicate failed
Reason_loop_limit_check, // compiler generated loop limits check
// failed
Reason_speculate_class_check, // saw unexpected object class from type
// speculation
Reason_speculate_null_check, // saw unexpected null from type speculation
Reason_speculate_null_assert, // saw unexpected null from type speculation
Reason_rtm_state_change, // rtm state change detected
Reason_unstable_if, // a branch predicted always false was taken
Reason_unstable_fused_if, // fused two ifs that had each one untaken
// branch. One is now taken.
java.lang.String.equals()
直接相关的更有趣的示例-您的场景:
String a = "a";
Object b = "b";
int i = 0;
while (true) {
if (++i == 100000000) {
System.out.println("Calling a.equals(b) with b = null");
b = null;
}
a.equals(b);
}
String
实例开始。经过一亿次比较,它将
b
设置为
null
并继续。这就是此时发生的情况(为了便于阅读,对其进行了缩短/重新格式化):
Calling a.equals(b) with b = null
Uncommon trap occurred in java.lang.String::equals
reason=null_check
action=make_not_entrant
703 10 4 java.lang.String::equals (81 bytes) made not entrant
DEOPT PACKING thread 0x00007f7aac00d800 Compiled frame
nmethod 703 10 4 java.lang.String::equals (81 bytes)
Virtual frames (innermost first):
java.lang.String.equals(String.java:968) - instanceof @ bci 8
DEOPT UNPACKING thread 0x00007f7aac00d800
{method} {0x00007f7a9b0d7290} 'equals' '(Ljava/lang/Object;)Z'
in 'java/lang/String' - instanceof @ bci 8 sp = 0x00007f7ab2ac3700
712 14 4 java.lang.String::equals (81 bytes)
instanceof
(
java.lang.String.equals()
)使用的
if (anObject instanceof String) {
中的null检查,因为
b
绝不会为null。经过一亿次运算后,该不变式被违反,并且陷阱被触发,从而导致使用空检查进行重新编译。
null
开头并在一亿次迭代后分配
b
来扭转局面,以说明另一个非优化原因:
String a = "a";
Object b = null;
int i = 0;
while (true) {
if (++i == 100000000) {
System.out.println("Calling a.equals(b) with b = 'b'");
b = "b";
}
a.equals(b);
}
Calling a.equals(b) with b = 'b'
Uncommon trap occurred in java.lang.String::equals
reason=unstable_if
action=reinterpret
695 10 4 java.lang.String::equals (81 bytes) made not entrant
DEOPT PACKING thread 0x00007f885c00d800
nmethod 695 10 4 java.lang.String::equals (81 bytes)
Virtual frames (innermost first):
java.lang.String.equals(String.java:968) - ifeq @ bci 11
DEOPT UNPACKING thread 0x00007f885c00d800
{method} {0x00007f884c804290} 'equals' '(Ljava/lang/Object;)Z'
in 'java/lang/String' - ifeq @ bci 11 sp = 0x00007f88643da700
705 14 2 java.lang.String::equals (81 bytes)
735 17 4 java.lang.String::equals (81 bytes)
744 14 2 java.lang.String::equals (81 bytes) made not entrant
instanceof
条件(
if (anObject instanceof String) {
)相对应的分支永远不会被采用,因为
anObject
始终为空。可以消除包括条件在内的整个代码块。在进行了1亿次运算后,该不变式被违反,并且陷阱被触发,从而导致重新编译/解释而没有消除分支。
关于java - 为什么Java Just in Time Compiler会继续重新编译相同的方法并使方法成为非租用的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61890873/
是 if(a == 0 && b == 0 && c == 0) { return; } 一样 if(a == 0) { return; } if(b == 0) { return; } if(c =
我想做这样的事情: Class A Class B extends A Class C extends A B b = new B(); C c = new C(); b->setField("foo
我对 Mysql 世界很天真......:)我试图使用连接从表中查询, 我遇到结果集问题...表结构如下 下面... VIDEO_XXXXX | Field | Type
我最近问过关于从另一个类获取类的唯一实例的问题。 ( How to get specific instance of class from another class in Java? ) 所以,我正
假设我们有两种类型 using t1 = int*; using t2 = int*; 我知道 std::is_same::value会给我们true .什么是,或者是否有模板工具可以实现以下目标?
对于我的一个应用程序,我假设比较 2 个字符串的第一个字符比比较整个字符串是否相等要快。例如,如果我知道只有 2 个可能的字符串(在一组 n 字符串中)可以以相同的字母开头(比如说 'q'),如果是这
我想在我的NXP LPC11U37H主板(ARM Cortex-M0)上分析一些算法,因为我想知道执行特定算法需要多少个时钟周期。 我编写了这些简单的宏来进行一些分析: #define START_C
我在 Excel 中创建了一个宏,它将在 Excel 中复制一个表格,并将行除以我确定的特定数字(默认 = 500 行),并为宏创建的每个部门打开不同的工作表。 使用的代码是这样的: Sub Copy
我想根据第一个字典对第二个字典的值求和。如果我有字典 A 和 B。 A = {"Mark": ["a", "b", "c", "d"], "June": ["e", "a"], "John": ["a
当我这样做时 system()在 Perl 中调用,我通常根据 perldocs 检查返回码.嗯,我是这么想的。大部分时间 $rc!=0对我来说已经足够了。最近我在这里帮助了两个遇到问题的人syste
在我的进度条上,我试图让它检测 div 加载速度。 如果 div 加载速度很快,我想要实现的目标将很快达到 100%。但进度条的加载速度应该与 div 的加载速度一样快。 问题:如何让我的进度条加载
当我获得与本地时间相同的时间戳时,firebase 生成的服务器时间戳是否会自动转换为本地时间,或者我错过了什么? _firestore.collection("9213903123").docume
根据the original OWL definition of OWL DL ,我们不能为类和个体赋予相同的名称(这是 OWL DL 和 OWL Full 之间的明显区别)。 "Punning" i
我有两个输入复选框: 尝试使用 jQuery 来允许两个输入的行为相同。如果选中第一个复选框,则选中第二个复选框。如果未检查第 1 个,则不会检查第 2 个。反之亦然。 我有代码: $('inpu
可以从不同系统编译两个相同的java文件,但它们都有相同的内容操作系统(Windows 7),会生成不同的.class文件(大小)? 最佳答案 是的,您可以检查是否有不同版本的JDK(Java Dev
我正在清理另一个人的正则表达式,他们目前所有的都以结尾 .*$ 那么下面的不是完全一样吗? .* 最佳答案 .*将尽可能匹配,但默认情况下为 .不匹配换行符。如果您要匹配的文本有换行符并且您处于 MU
我使用 Pick ,但是如何编写可以选择多个字段的通用PickMulti呢? interface MyInterface { a: number, b: number, c: number
我有一个 SQL 数据库服务器和 2 个具有相同结构和数据的数据库。我在 2 个数据库中运行相同的 sql 查询,其中一个需要更长的时间,而另一个在不到 50% 的时间内完成。他们都有不同的执行计划。
我需要你的帮助,我有一个包含两列的表,一个 id 和 numpos,我希望 id 和 numops 具有相同的结果。 例子: $cnx = mysql_connect( "localhost", "r
如何将相同的列(在本例中按“级别”排序)放在一起?我正在做一个高分,我从我的数据库中按级别列出它们。如果他们处于同一级别,我希望他们具有相同的 ID。 但是我不想在别人身上显示ID。只有第一个。这是一
我是一名优秀的程序员,十分优秀!