我有一个接口(interface)PackedObject:
public interface PackedObject {
int get();
int sum();
void setIndex(int index);
default int defaultSum() {
return get();
}
}
一个抽象类AbstractPackedObject:
public abstract class AbstractPackedObject implements PackedObject {
protected int index = 0;
protected int[] buffer;
public void setIndex(int index) {
this.index = index;
}
public void setBuffer(int[] buffer) {
this.buffer = buffer;
}
@Override
public int sum(){
return get();
}
}
以及一个具体的实现WrappedPackedObject:
public class WrappedPackedObject extends AbstractPackedObject implements PackedObject {
public WrappedPackedObject(int[] buffer) {
this.buffer = buffer;
}
@Override
public int get() {
return buffer[index];
}
}
我对 defaultSum 和 sum 方法进行了基准测试(JMH 基准测试的片段):
for (int i = 0; i < NB; i++) {
packedObject.setIndex(i);
value += packedObject.defaultSum();
}
for (int i = 0; i < NB; i++) {
packedObject.setIndex(i);
value += packedObject.sum();
}
我试图弄清楚为什么 sum 基准测试程序比 defaultSum 基准测试程序快 1.7 倍。
我已经开始深入研究 JIT 的奥秘了。调用站点仅针对一种方法,因此我希望完成内联。打印内联的输出如下:
@ 25 com.github.nithril.PackedObject::defaultSum (7 bytes) inline (hot)
\-> TypeProfile (479222/479222 counts) = com/github/nithril/WrappedPackedObject
@ 1 com.github.nithril.WrappedPackedObject::get (14 bytes) inline (hot)
@ 10 java.nio.DirectByteBuffer::getInt (15 bytes) inline (hot)
@ 25 com.github.nithril.AbstractPackedObject::sum (5 bytes) inline (hot)
@ 1 com.github.nithril.WrappedPackedObject::get (14 bytes) inline (hot)
@ 10 java.nio.DirectByteBuffer::getInt (15 bytes) inline (hot)
我还不明白为什么会出现这一行 TypeProfile (479222/479222 counts) = com/github/nithril/WrappedPackedObject
我创建了一个 dedicated project用上面的代码。基准测试是使用 JMH 完成的。
感谢您的帮助。
编辑 2015/05/20:
我简化了java代码。
benchSum 的内部循环非常简单:
0x00007f1bb11afb84: add 0x10(%r10,%r8,4),%eax ;*iadd
; - com.github.nithril.PackedObjectBench::benchSum@29 (line 50)
0x00007f1bb11afb89: mov %r8d,0xc(%r12,%r11,8) ;*putfield index
; - com.github.nithril.AbstractPackedObject::setIndex@2 (line 13)
; - com.github.nithril.PackedObjectBench::benchSum@17 (line 49)
0x00007f1bb11afb8e: inc %r8d ;*iinc
; - com.github.nithril.PackedObjectBench::benchSum@31 (line 48)
0x00007f1bb11afb91: cmp $0x2710,%r8d
0x00007f1bb11afb98: jl 0x00007f1bb11afb84
benchDefaultSum 的内部循环更复杂,因为索引的读/写和内部循环内部数组绑定(bind)的比较。我还没有完全理解这个比较的目的......
0x00007fcfdcf82cb8: mov %edx,0xc(%r12,%r11,8) ;*putfield index
; - com.github.nithril.AbstractPackedObject::setIndex@2 (line 13)
; - com.github.nithril.PackedObjectBench::benchDefaultSum@17 (line 32)
0x00007fcfdcf82cbd: mov 0xc(%r10),%r8d ;*getfield index
; - com.github.nithril.WrappedPackedObject::get@5 (line 17)
; - com.github.nithril.PackedObject::defaultSum@1 (line 15)
; - com.github.nithril.PackedObjectBench::benchDefaultSum@24 (line 33)
0x00007fcfdcf82cc1: cmp %r9d,%r8d
0x00007fcfdcf82cc4: jae 0x00007fcfdcf82d1f ;*iaload
; - com.github.nithril.WrappedPackedObject::get@8 (line 17)
; - com.github.nithril.PackedObject::defaultSum@1 (line 15)
; - com.github.nithril.PackedObjectBench::benchDefaultSum@24 (line 33)
0x00007fcfdcf82cc6: add 0x10(%rcx,%r8,4),%eax ;*iadd
; - com.github.nithril.PackedObjectBench::benchDefaultSum@29 (line 33)
0x00007fcfdcf82ccb: inc %edx ;*iinc
; - com.github.nithril.PackedObjectBench::benchDefaultSum@31 (line 31)
0x00007fcfdcf82ccd: cmp $0x2710,%edx
0x00007fcfdcf82cd3: jl 0x00007fcfdcf82cb8 ;*aload_2
[...]
0x00007fcfdcf82ce6: mov $0xffffffe4,%esi
0x00007fcfdcf82ceb: mov %r10,0x8(%rsp)
0x00007fcfdcf82cf0: mov %ebx,0x4(%rsp)
0x00007fcfdcf82cf4: mov %r8d,0x10(%rsp)
0x00007fcfdcf82cf9: xchg %ax,%ax
0x00007fcfdcf82cfb: callq 0x00007fcfdcdea1a0 ; OopMap{rbp=NarrowOop [8]=Oop off=416}
;*iaload
; - com.github.nithril.WrappedPackedObject::get@8 (line 17)
; - com.github.nithril.PackedObject::defaultSum@1 (line 15)
; - com.github.nithril.PackedObjectBench::benchDefaultSum@24 (line 33)
; {runtime_call}
0x00007fcfdcf82d00: callq 0x00007fcff1c94320 ;*iaload
; - com.github.nithril.WrappedPackedObject::get@8 (line 17)
; - com.github.nithril.PackedObject::defaultSum@1 (line 15)
; - com.github.nithril.PackedObjectBench::benchDefaultSum@24 (line 33)
; {runtime_call}
[...]
0x00007fcfdcf82d1f: mov %eax,(%rsp)
0x00007fcfdcf82d22: mov %edx,%ebx
0x00007fcfdcf82d24: jmp 0x00007fcfdcf82ce6
最佳答案
我只是通过粗略阅读 hotspot-compiler-dev 获得的反刍信息邮件列表,但这可能是接口(interface)中的默认方法缺少类层次结构分析,这阻碍了接口(interface)方法的去虚拟化。
我的猜测是,即使该方法是内联的,它前面仍然有一个类型保护,在抽象情况下会被 CHA 消除,但对于接口(interface)方法却不是。
打印优化程序集(我认为 JMH 对此有一些标志)可以证实这一点。
关于Java 默认方法比相同的代码慢,但在抽象类中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30312096/
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问
两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题: