Moh*_*agi 108 java string string-concatenation invokedynamic java-9
正如JEP 280中所写:
更改
String
生成的static -concatenation字节码序列,javac
以使用invokedynamic
对JDK库函数的调用.这将使未来的String
串联优化成为可能,而无需进一步更改所设置的字节码javac
.
在这里,我想了解invokedynamic
调用的用途以及字节码串联的不同之处是invokedynamic
什么?
T.J*_*der 93
"旧"方式输出一堆StringBuilder
定向操作.考虑这个程序:
public class Example {
public static void main(String[] args)
{
String result = args[0] + "-" + args[1] + "-" + args[2];
System.out.println(result);
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们使用JDK 8或更早版本编译它然后javap -c Example
用来查看字节码,我们会看到如下内容:
public class Example { public Example(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class java/lang/StringBuilder 3: dup 4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V 7: aload_0 8: iconst_0 9: aaload 10: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 13: ldc #5 // String - 15: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 18: aload_0 19: iconst_1 20: aaload 21: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: ldc #5 // String - 26: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 29: aload_0 30: iconst_2 31: aaload 32: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 35: invokevirtual #6 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 38: astore_1 39: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 42: aload_1 43: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 46: return }
如您所见,它创建了一个StringBuilder
并使用append
.这是着名的低效率,因为内置缓冲区的默认容量StringBuilder
只有16个字符,并且编译器无法预先分配更多,因此最终必须重新分配.它也是一堆方法调用.(请注意,JVM 有时可以检测并重写这些调用模式,以提高它们的效率.)
让我们看看Java 9生成的内容:
public class Example { public Example(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: aload_0 1: iconst_0 2: aaload 3: aload_0 4: iconst_1 5: aaload 6: aload_0 7: iconst_2 8: aaload 9: invokedynamic #2, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 14: astore_1 15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 18: aload_1 19: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 22: return }
哦,我的,但那更短.:-)它对makeConcatWithConstants
from 进行一次调用StringConcatFactory
,在Javadoc中说这个:
方便创建字符串连接方法的方法,可用于有效地连接已知类型的已知类型的参数,可能在类型调整和参数的部分评估之后.这些方法通常用作引导方法的
invokedynamic
调用处,支持字符串连接 Java编程语言的特点.
Nam*_*man 20
在进入invokedynamic
用于优化字符串连接的实现的细节之前,在我看来,必须得到一些关于什么是invokedynamic的背景知识以及如何使用它?
该
invokedynamic
指令简化并可能改进JVM上动态语言的编译器和运行时系统的实现.它通过允许语言实现者使用invokedynamic
涉及以下步骤的指令定义自定义链接行为来实现此目的.
我可能会尝试通过为实现字符串连接优化而带来的更改来引导您完成这些操作.
定义Bootstrap方法: - 使用Java9,invokedynamic
调用站点的引导方法,主要支持字符串连接makeConcat
,makeConcatWithConstants
并随StringConcatFactory
实现一起引入.
使用invokedynamic提供了在运行时选择转换策略的替代方法.使用的转换策略StringConcatFactory
类似于LambdaMetafactory
之前的java版本中引入的转换策略.此外,问题中提到的JEP的目标之一是进一步扩展这些策略.
指定常量池条目: - 这些是除了invokedynamic
(1)MethodHandles.Lookup
对象之外的指令的附加静态参数,该对象是用于在invokedynamic
指令的上下文中创建方法句柄的工厂,(2)String
对象,动态调用中提到的方法名称站点和(3)MethodType
对象,动态调用站点的已解析类型签名.
在链接代码期间已经链接了.在运行时,引导方法运行并链接到实际代码中进行连接.它invokedynamic
通过适当的invokestatic
呼叫重写呼叫.这将从常量池加载常量字符串,利用bootstrap方法static args将这些和其他常量直接传递给bootstrap方法调用.
使用invokedynamic指令: - 通过在初始调用期间提供一次引导调用目标的方法,为延迟链接提供了便利.这里优化的具体想法是StringBuilder.append
用简单的invokedynamic
调用替换整个舞蹈java.lang.invoke.StringConcatFactory
,这将接受需要连接的值.
所述Indify字符串连接建议用一个例子指出与Java9应用程序,其中一个相似的方法如通过共享的基准@TJ克劳德被编译并在字节码的差变化的执行之间相当可见.
Eug*_*ene 17
我在这里稍微添加一些细节.要获得的主要部分是字符串连接如何完成是运行时决定,而不是编译时间.因此它可以改变,这意味着您已经针对java-9编译了一次代码,并且它可以更改底层实现,但不需要重新编译.
第二点是目前有6 possible strategies for concatenation of String
:
private enum Strategy {
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder}.
*/
BC_SB,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but trying to estimate the required storage.
*/
BC_SB_SIZED,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but computing the required storage exactly.
*/
BC_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also tries to estimate the required storage.
*/
MH_SB_SIZED,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also estimate the required storage exactly.
*/
MH_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that constructs its own byte[] array from
* the arguments. It computes the required storage exactly.
*/
MH_INLINE_SIZED_EXACT
}
Run Code Online (Sandbox Code Playgroud)
您可以通过参数选择其中任何一个:-Djava.lang.invoke.stringConcat
.请注意,这StringBuilder
仍然是一个选项.