我一直听说有关添加到JVM的所有新酷功能,其中一个很酷的功能是invokedynamic.我想知道它是什么以及它如何使Java中的反射编程更容易或更好?
正如JEP 280中所写:
更改
String生成的static -concatenation字节码序列,javac以使用invokedynamic对JDK库函数的调用.这将使未来的String串联优化成为可能,而无需进一步更改所设置的字节码javac.
在这里,我想了解invokedynamic调用的用途以及字节码串联的不同之处是invokedynamic什么?
我正在研究JDK 1.7的新功能,我无法得到它为MethodHandle设计的内容?我理解(直接)静态方法的调用(以及在这种情况下直接使用Core Reflection API).我也理解(直接)调用虚方法(非静态,非最终)(以及使用需要通过Class层次结构的Core Reflection API obj.getClass().getSuperclass()).非虚方法的调用可以视为前者的特殊情况.
是的,我知道存在重载问题.如果要调用方法,则必须提供确切的签名.您无法以简单的方式检查重载方法.
但是,MethodHandle是什么?Reflection API允许您"查看"对象内部,而无需任何预先假设(如实现接口).您可以出于某种目的检查对象.但是MethodHandle的设计是什么呢?我应该何时何地使用它?
更新:我现在正在阅读这篇http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html文章.根据它,主要目标是简化在JVM上运行的脚本语言的生命,而不是Java语言本身.
更新-2:我读完了上面的链接,从那里引用了一些引文:
JVM将成为构建动态语言的最佳VM,因为它已经是一个动态语言VM.而InvokeDynamic通过向一流的JVM公民推广动态语言,将证明这一点.
使用反射来调用方法效果很好......除了一些问题.必须从特定类型检索方法对象,并且不能以一般方式创建.<...>
...反射调用比直接调用慢很多.多年来,JVM已经非常擅长快速反映调用.现代JVM实际上在幕后生成了一堆代码,以避免处理大量开销的旧JVM.但简单的事实是,通过任意数量的层反射访问总是比直接调用慢,部分原因是完全通用的"调用"方法必须检查并重新检查接收器类型,参数类型,可见性和其他细节,但因为参数必须都是对象(所以原语是对象框),并且必须作为一个数组提供,以涵盖所有可能的arities(所以参数得到数组框).
对于执行少量反射调用的库,性能差异可能无关紧要,特别是如果这些调用主要是为了在内存中动态设置静态结构,可以进行正常调用.但是在动态语言中,每次调用必须使用这些机制,这是一个严重的性能损失.
http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html
因此,对于Java程序员来说,它基本上是无用的.我对吗?从这个角度来看,它只能被视为Core Reflection API的替代方式.
Rich Hickey和其他人已经提到Clojure不会从即将推出invokeDynamic的JVM 7或8计划中获得显着改进,但是会看到尾递归的性能提升.
尾递归是否会对其产生影响
(fn [...] (recur ...))
Run Code Online (Sandbox Code Playgroud)
要么
(loop [...] (recur ...))
Run Code Online (Sandbox Code Playgroud)
我不希望它们得到任何更快,因为编译器可能已经生成循环结构.
我已经阅读了"Groovy 2.0中的新功能",我对何时使用@CompileStatic感到有些困惑.文章提到@CompileStatic为没有能够利用Java7的调用动态部分的开发人员添加了注释.
因此,如果无法在JDK 7上运行,那么寻求性能改进的开发人员不会看到Groovy 2.0中的太多变化.幸运的是,Groovy开发团队认为这些开发人员可以通过允许类型检查来获得有趣的性能提升等优势代码要静态编译.
我的问题是,如果我使用JDK 7并按照说明添加--indy标志,我是否需要添加@CompileStatic才能看到性能提升? 这个博客暗示我会,但我不确定他是否正确编译,因为他在Eclipse中做到了.
更新:以下是运行Fibonacci代码的不同排列时的统计信息.
> groovy --indy FibBoth.groovy
..........Fib (non-static indy): 1994.465
..........Fib (static indy): 529.197
> groovy FibBoth.groovy
..........Fib (non-static): 1212.788
..........Fib (static): 525.671
Run Code Online (Sandbox Code Playgroud)
注意:现在我明白这些功能是独立的,这个问题似乎有点混乱.由于问题的基础是围绕着使我认为两个特征相关的注释的混淆,我认为不改变问题措辞并允许解释差异的接受答案是有道理的.
MethodType methodType = MethodType.methodType(void.class, ByteBuffer.class);
MethodHandle handle = MethodHandles.publicLookup().findConstructor(type, methodType);
Function<ByteBuffer, Object> = handle; // ???
Run Code Online (Sandbox Code Playgroud)
是否有可能让最后的作业有效?反转方式不起作用:是否可以将方法引用转换为MethodHandle?
这是另一个可复制的例子:
new Integer("123");
MethodType methodType = MethodType.methodType(void.class, String.class);
MethodHandle handle = MethodHandles.publicLookup().findConstructor(Integer.class, methodType);
Function<String, Integer> function1 = Integer::new;
Function<String, Integer> function2 = handle.toLambda(); // ???
Run Code Online (Sandbox Code Playgroud) 我正在尝试在运行时编译和加载动态生成的 Java 代码。由于 ClassLoader::defineClass 和 Unsafe::defineAnonymousClass 在这种情况下都有严重的缺点,因此我尝试通过Lookup::defineHiddenClass使用隐藏类。这对于我尝试加载的所有类都适用,但调用 lambda 表达式或包含匿名类的类除外。
调用 lambda 表达式会引发以下异常:
Exception in thread "main" java.lang.NoClassDefFoundError: tests/HiddenClassLambdaTest$LambdaRunner/0x0000000800c04400
at tests.HiddenClassLambdaTest.main(HiddenClassLambdaTest.java:22)
Caused by: java.lang.ClassNotFoundException: tests.HiddenClassLambdaTest$LambdaRunner.0x0000000800c04400
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:636)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:182)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:519)
... 1 more
Run Code Online (Sandbox Code Playgroud)
执行实例化匿名类的代码会引发以下错误:
Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
Location:
tests/HiddenClassLambdaTest$LambdaRunner+0x0000000800c00400.run()V @5: invokespecial
Reason:
Type 'tests/HiddenClassLambdaTest$LambdaRunner+0x0000000800c00400' (current frame, stack[2]) is not assignable to 'tests/HiddenClassLambdaTest$LambdaRunner'
Current Frame:
bci: @5
flags: { }
locals: { 'tests/HiddenClassLambdaTest$LambdaRunner+0x0000000800c00400' }
stack: { uninitialized 0, uninitialized …Run Code Online (Sandbox Code Playgroud) 是否有估计表明JSR-292会对Groovy的性能产生多大影响?
我真的很喜欢Grails,但我想知道如何获得Groovy 2的性能优势.问题是如何配置开发和生产环境以获得"接近Java"性能提升.
所以,如果我设置:
* JDK 7
* Groovy 2 (indie JAR to use invokedynamic)
* Grails 2.2
Run Code Online (Sandbox Code Playgroud)
是否有任何指导方针,以真正加快我的webapp 开箱即用?
我是否需要在Grails webapp代码库中进行任何重新分解?我的意思是依赖注入的东西,如控制器中的引用服务应该静态编译,或者我应该像文档说的那样继续编写代码?
ps:我猜Groovy @CompileStatic和Grails可能是一个相关的问题......
我想尝试避免反射调用构造函数,并尝试遵循本文中采用的LamdaMetaFactory方法 - 更快地替代Java的反射
我想要构建的类看起来像:
interface DBBroker {}
public class NativeBroker implements DBBroker {
public NativeBroker(BrokerPool brokerPool, final Configuration configuration) {
}
}
Run Code Online (Sandbox Code Playgroud)
使用LambaMetaFactory我试图构造一个BiFunction<BrokerPool, Configuration, DBBroker>替换直接调用构造函数.
到目前为止我的代码看起来像:
Class<? extends DBBroker> clazz =
(Class<? extends DBBroker>) Class.forName("org.exist.storage.NativeBroker");
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh =
lookup.findConstructor(clazz, MethodType.methodType(void.class, new Class[] {BrokerPool.class, Configuration.class}));
BiFunction<BrokerPool, Configuration, DBBroker> constructor
(BiFunction<BrokerPool, Configuration, DBBroker>)
LambdaMetafactory.metafactory(
lookup, "apply", MethodType.methodType(BiFunction.class),
mh.type(), mh, mh.type()).getTarget().invokeExact();
final DBBroker broker = constructor.apply(database, conf);
Run Code Online (Sandbox Code Playgroud)
不幸的是,这会返回错误 -
AbstractMethodError:方法org/exists/storage/BrokerFactory $$ Lambda $ 55.apply(Ljava/lang/Object; Ljava/lang/Object;)Ljava/lang/Object; …
invokedynamic ×10
java ×7
groovy ×3
java-7 ×3
java-8 ×2
lambda ×2
reflection ×2
classloader ×1
clojure ×1
grails ×1
groovy-2 ×1
java-15 ×1
java-9 ×1
jep ×1
jvm ×1
methodhandle ×1
performance ×1
string ×1