我正在编写一些调用field.set
和field.get
几千次的代码。显然这是非常缓慢的,因为反射。
我想看看是否可以在Java7中使用methodhandle
来提高性能。到目前为止,我有以下资料:
不是field.set(pojo,value)
,而是:
private static final Map<Field, MethodHandle> setHandles = new HashMap<>();
MethodHandle mh = setHandles.get(field);
if (mh == null) {
mh = lookup.unreflectSetter(field);
setHandles.put(field, mh);
}
mh.invoke(pojo, value);
但是,这似乎并不比使用反射的field.set调用执行得更好。我是不是做错什么了?
我读到使用InvokeExact
可能更快,但当我尝试使用它时,我得到了一个java.lang.Invoke.WrongMethodTypeException
。
是否有人成功地优化了对field.set或field.get的重复调用?
2015-06-01:更新以反映@joec关于句柄是静态的另一种情况的评论。也更新到最新的JMH和重新运行的现代硬件。结论几乎保持不变。
请做适当的基准测试,这对JMH来说并不是那么难。一旦你这么做了,答案就变得显而易见了。它还可以展示invokeexact
的正确使用(需要目标/源1.7才能编译和运行):
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class MHOpto {
private int value = 42;
private static final Field static_reflective;
private static final MethodHandle static_unreflect;
private static final MethodHandle static_mh;
private static Field reflective;
private static MethodHandle unreflect;
private static MethodHandle mh;
// We would normally use @Setup, but we need to initialize "static final" fields here...
static {
try {
reflective = MHOpto.class.getDeclaredField("value");
unreflect = MethodHandles.lookup().unreflectGetter(reflective);
mh = MethodHandles.lookup().findGetter(MHOpto.class, "value", int.class);
static_reflective = reflective;
static_unreflect = unreflect;
static_mh = mh;
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}
@Benchmark
public int plain() {
return value;
}
@Benchmark
public int dynamic_reflect() throws InvocationTargetException, IllegalAccessException {
return (int) reflective.get(this);
}
@Benchmark
public int dynamic_unreflect_invoke() throws Throwable {
return (int) unreflect.invoke(this);
}
@Benchmark
public int dynamic_unreflect_invokeExact() throws Throwable {
return (int) unreflect.invokeExact(this);
}
@Benchmark
public int dynamic_mh_invoke() throws Throwable {
return (int) mh.invoke(this);
}
@Benchmark
public int dynamic_mh_invokeExact() throws Throwable {
return (int) mh.invokeExact(this);
}
@Benchmark
public int static_reflect() throws InvocationTargetException, IllegalAccessException {
return (int) static_reflective.get(this);
}
@Benchmark
public int static_unreflect_invoke() throws Throwable {
return (int) static_unreflect.invoke(this);
}
@Benchmark
public int static_unreflect_invokeExact() throws Throwable {
return (int) static_unreflect.invokeExact(this);
}
@Benchmark
public int static_mh_invoke() throws Throwable {
return (int) static_mh.invoke(this);
}
@Benchmark
public int static_mh_invokeExact() throws Throwable {
return (int) static_mh.invokeExact(this);
}
}
在1x4x2 i7-4790K、JDK 8U40、Linux x86_64上生成:
Benchmark Mode Cnt Score Error Units
MHOpto.dynamic_mh_invoke avgt 25 4.393 ± 0.003 ns/op
MHOpto.dynamic_mh_invokeExact avgt 25 4.394 ± 0.007 ns/op
MHOpto.dynamic_reflect avgt 25 5.230 ± 0.020 ns/op
MHOpto.dynamic_unreflect_invoke avgt 25 4.404 ± 0.023 ns/op
MHOpto.dynamic_unreflect_invokeExact avgt 25 4.397 ± 0.014 ns/op
MHOpto.plain avgt 25 1.858 ± 0.002 ns/op
MHOpto.static_mh_invoke avgt 25 1.862 ± 0.015 ns/op
MHOpto.static_mh_invokeExact avgt 25 1.859 ± 0.002 ns/op
MHOpto.static_reflect avgt 25 4.274 ± 0.011 ns/op
MHOpto.static_unreflect_invoke avgt 25 1.859 ± 0.002 ns/op
MHOpto.static_unreflect_invokeExact avgt 25 1.858 ± 0.002 ns/op
...这表明在这种情况下,MH确实比反射快得多(这是因为针对私有字段的访问检查是在查找时进行的,而不是在调用时进行的)。dynamic_*
情况模拟methodhandles
和/或字段
不是静态已知的情况,例如从map
static_*
情况是调用者静态已知的情况。
注意,在
dynamic_*
情况下,反射性能与MethodHandles相当,这是因为反射在JDK 8中进一步进行了大量优化(因为实际上,您不需要访问检查来读取您自己的字段),所以答案可能是“仅仅”切换到JDK 8;)
static_*
情况甚至更快,因为methandles.invoke
调用是积极内联的。这消除了MH情况下的部分类型检查。但是,在反射情况下,仍然存在快速检查,因此,它滞后。
问题内容: 我正在编写一些可调用的代码,并且执行了数千次。显然,由于反射,这非常慢。 我想看看是否可以在Java 7中使用以提高性能。到目前为止,这里是我所拥有的: 代替,我在做: 但是,这似乎并不比使用反射的Field.set调用更好。我在这里做错什么了吗? 我读到使用可能会更快,但是当我尝试使用它时,得到了。 有谁成功地优化了对Field.set或Field.get的重复调用? 问题答案: 2
我有一个名为Emails的列族,我正在将邮件保存到这个CF中,编写5000封邮件需要100秒。 我使用的是i3处理器,8gb内存。我的数据中心有6个节点,复制因子=2。 我们存储在卡桑德拉中的数据大小会影响性能吗?影响写入性能的所有因素是什么,如何提高性能? 预先感谢..
问题内容: 我在基于JBoss的Web应用程序中使用JAXBContext.newInstance操作。据我了解,此操作非常繁重。我只需要Marshaller类的两个唯一实例。 我最初的建议是要有一个静态初始值设定项块,该类将在加载类时仅初始化一次这两个实例: 如果这是一个合理的解决方案,那么我想我会回答自己的问题,但是我想知道这是否是正确的方法? 问题答案: JAXB实现(Metro,Eclip
问题内容: 我在公司中多次设计数据库。为了提高数据库的性能,我只寻找标准化和索引。 如果要求您提高数据库的性能,该数据库包含大约250个表以及一些具有数百万个记录的表,那么您将寻找什么不同的东西? 提前致谢。 问题答案: 优化逻辑设计 逻辑级别是关于查询和表本身的结构。首先尝试最大程度地发挥这一作用。目标是在逻辑级别上访问尽可能少的数据。 拥有最高效的SQL查询 设计支持应用程序需求的逻辑架构(例
我正在编写spring批处理,它从平面文件中读取数据,很少进行处理,并将摘要写入输出文件。与reader相比,我的处理器和写入程序相对更快。我正在使用FlatFileItemReader,并尝试了从50-1000开始的各种提交间隔。我的批处理作业必须以更快的速度处理1000万条记录。请告诉我如何提高FlatFileItemReader的速度。粘贴到我的配置文件和映射器类下面,读取字段集并将值设置为
我正在开发和运行基于groovy的Jenkins管道作业,我们的代码执行多个线程,需要高CPU和内存。 由于JProfiler是一个功能强大的Java评测工具,因此我想在Jenkins管道作业中收集有关我的groovy代码的性能信息,这些作业在代理上运行,因此我将能够排除代码缺陷并优化代码。 安装JProfiler的最佳实践是什么?(远程KVM或在Jenkins或本地代理上?)