类型名称 likecom.example.Dog
将被编译到com/example/Dog
.class 文件中。大多数JVM将如何优化它?似乎更长的类型名称(或成员名称)需要更多的字符串比较。
问问题
468 次
3 回答
8
长类型(类和接口)名称在符号表中占据空间。这些名称在链接时使用,如Java 虚拟机规范的第 5 章中详细描述的那样。完成所有这些链接后,除非您使用反射,否则名称对运行时性能没有影响。
于 2012-05-18T04:34:39.503 回答
5
java编译器生成字节码,没有字符串比较。
用 javap 检查这个类并查看字节码。
例如,这个
class A extends java.lang.Object{
static final boolean $assertionsDisabled;
A();
public static void main(java.lang.String[]);
static {};
}
转这个
class A extends java.lang.Object{
static final boolean $assertionsDisabled;
A();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field $assertionsDisabled:Z
3: ifne 14
6: new #3; //class java/lang/AssertionError
9: dup
10: invokespecial #4; //Method java/lang/AssertionError."<init>":()V
13: athrow
14: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
17: ldc #6; //String hi
19: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
22: return
static {};
Code:
0: ldc_w #8; //class A
3: invokevirtual #9; //Method java/lang/Class.desiredAssertionStatus:()Z
6: ifne 13
9: iconst_1
10: goto 14
13: iconst_0
14: putstatic #2; //Field $assertionsDisabled:Z
17: return
}
jvm 在内部使用数字 ID。长变量名和短变量名之间没有区别。
编辑:添加 -l 输出
Compiled from "A.java"
class A extends java.lang.Object{
static final boolean $assertionsDisabled;
A();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field $assertionsDisabled:Z
3: ifne 14
6: new #3; //class java/lang/AssertionError
9: dup
10: invokespecial #4; //Method java/lang/AssertionError."<init>":()V
13: athrow
14: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
17: ldc #6; //String hi
19: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
22: return
LineNumberTable:
line 6: 0
line 7: 14
line 8: 22
static {};
Code:
0: ldc_w #8; //class A
3: invokevirtual #9; //Method java/lang/Class.desiredAssertionStatus:()Z
6: ifne 13
9: iconst_1
10: goto 14
13: iconst_0
14: putstatic #2; //Field $assertionsDisabled:Z
17: return
LineNumberTable:
line 3: 0
}
并添加 -verbose -s
Compiled from "A.java"
class A extends java.lang.Object
SourceFile: "A.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #10.#23; // java/lang/Object."<init>":()V
const #2 = Field #8.#24; // A.$assertionsDisabled:Z
const #3 = class #25; // java/lang/AssertionError
const #4 = Method #3.#23; // java/lang/AssertionError."<init>":()V
const #5 = Field #26.#27; // java/lang/System.out:Ljava/io/PrintStream;
const #6 = String #28; // hi
const #7 = Method #29.#30; // java/io/PrintStream.println:(Ljava/lang/String;)V
const #8 = class #31; // A
const #9 = Method #32.#33; // java/lang/Class.desiredAssertionStatus:()Z
const #10 = class #34; // java/lang/Object
const #11 = Asciz $assertionsDisabled;
const #12 = Asciz Z;
const #13 = Asciz <init>;
const #14 = Asciz ()V;
const #15 = Asciz Code;
const #16 = Asciz LineNumberTable;
const #17 = Asciz main;
const #18 = Asciz ([Ljava/lang/String;)V;
const #19 = Asciz StackMapTable;
const #20 = Asciz <clinit>;
const #21 = Asciz SourceFile;
const #22 = Asciz A.java;
const #23 = NameAndType #13:#14;// "<init>":()V
const #24 = NameAndType #11:#12;// $assertionsDisabled:Z
const #25 = Asciz java/lang/AssertionError;
const #26 = class #35; // java/lang/System
const #27 = NameAndType #36:#37;// out:Ljava/io/PrintStream;
const #28 = Asciz hi;
const #29 = class #38; // java/io/PrintStream
const #30 = NameAndType #39:#40;// println:(Ljava/lang/String;)V
const #31 = Asciz A;
const #32 = class #41; // java/lang/Class
const #33 = NameAndType #42:#43;// desiredAssertionStatus:()Z
const #34 = Asciz java/lang/Object;
const #35 = Asciz java/lang/System;
const #36 = Asciz out;
const #37 = Asciz Ljava/io/PrintStream;;
const #38 = Asciz java/io/PrintStream;
const #39 = Asciz println;
const #40 = Asciz (Ljava/lang/String;)V;
const #41 = Asciz java/lang/Class;
const #42 = Asciz desiredAssertionStatus;
const #43 = Asciz ()Z;
{
static final boolean $assertionsDisabled;
Signature: Z
A();
Signature: ()V
LineNumberTable:
line 3: 0
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public static void main(java.lang.String[]);
Signature: ([Ljava/lang/String;)V
LineNumberTable:
line 6: 0
line 7: 14
line 8: 22
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #2; //Field $assertionsDisabled:Z
3: ifne 14
6: new #3; //class java/lang/AssertionError
9: dup
10: invokespecial #4; //Method java/lang/AssertionError."<init>":()V
13: athrow
14: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
17: ldc #6; //String hi
19: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
22: return
LineNumberTable:
line 6: 0
line 7: 14
line 8: 22
StackMapTable: number_of_entries = 1
frame_type = 14 /* same */
static {};
Signature: ()V
LineNumberTable:
line 3: 0
Code:
Stack=1, Locals=0, Args_size=0
0: ldc_w #8; //class A
3: invokevirtual #9; //Method java/lang/Class.desiredAssertionStatus:()Z
6: ifne 13
9: iconst_1
10: goto 14
13: iconst_0
14: putstatic #2; //Field $assertionsDisabled:Z
17: return
LineNumberTable:
line 3: 0
StackMapTable: number_of_entries = 2
frame_type = 13 /* same */
frame_type = 64 /* same_locals_1_stack_item */
stack = [ int ]
}
于 2012-05-18T04:28:56.320 回答
1
这部分取决于在 JIT 编译时是否可以解决实际的精确方法。如果可以,那么编译后的代码可以简单地分支到相关代码。例如,您可以在最终与非最终方法调用的这些时间中看到 Hotspot 这样做的证据。事实上,没有专门针对 final 方法的优化(这是我在开发人员中发现的常见误解)。但正如这些数字所示,对于可以确定精确方法的情况(无论是否最终确定),都存在优化。
如果无法识别精确的方法,那么 VM 至少可以对方法签名的哈希码进行操作,这样一旦针对从给定方法的给定字节码偏移量进行的调用计算了一次哈希码,它就不会需要重新计算。我承认我没有查看 Hotspot 或其他 JVM 是否真的这样做,但原则上这似乎是一件非常明显的事情。
于 2012-05-18T05:10:28.207 回答