静态块与静态方法 - 初始化静态字段
出于好奇,我测量了静态块和静态方法初始值设定项之间的性能。首先,我在两个单独的java类中实现了上述方法,如下所示:
First:
class Dummy {
static java.util.List<Integer> lista = new java.util.ArrayList<Integer>();
static {
for(int i=0; i < 1000000; ++i) {
lista.add(new Integer(i));
}
}
}
public class First {
public static void main(String[] args) {
long st = System.currentTimeMillis();
Dummy d = new Dummy();
long end = System.currentTimeMillis() - st;
System.out.println(end);
}
}
Second:
class Muddy {
static java.util.List<Integer> lista = new java.util.ArrayList<Integer>();
public static void initList() {
for(int i=0; i < 1000000; ++i) {
lista.add(new Integer(i));
}
}
}
public class Second {
public static void main(String[] args) {
long st = System.currentTimeMillis();
Muddy.initList();
Muddy m = new Muddy();
long end = System.currentTimeMillis() - st;
System.out.println(end);
}
}
然后我执行 this 小批处理脚本来测量 100 次并将值放入文件中。 batchFile.bat First Second dum.res.txt
之后,我写了这篇用于计算 Dummy 和 Muddy 测量值的平均值和标准偏差的代码。
这是我得到的结果:
First size: 100 Second size: 100
First Sum: 132 Std. deviation: 13
Second Sum: 112 Std. deviation: 9
每次我测试它时,它在我的其他机器上都是类似的。
现在我想知道,为什么会这样呢?我检查了字节码,Second.class 在调用 System.currentTimeMillis() 之间多了一条指令(调用静态 initList())。 他们都做同样的事情,但为什么第一个慢呢?我无法仅仅通过查看字节码来真正推理出它,因为这是我第一次接触javap;我还不懂字节码。
Out of curiosity, I measured the performance between static block and static method initializer. First, I implemented the above mentioned methods in two separate java classes, like so:
First:
class Dummy {
static java.util.List<Integer> lista = new java.util.ArrayList<Integer>();
static {
for(int i=0; i < 1000000; ++i) {
lista.add(new Integer(i));
}
}
}
public class First {
public static void main(String[] args) {
long st = System.currentTimeMillis();
Dummy d = new Dummy();
long end = System.currentTimeMillis() - st;
System.out.println(end);
}
}
Second:
class Muddy {
static java.util.List<Integer> lista = new java.util.ArrayList<Integer>();
public static void initList() {
for(int i=0; i < 1000000; ++i) {
lista.add(new Integer(i));
}
}
}
public class Second {
public static void main(String[] args) {
long st = System.currentTimeMillis();
Muddy.initList();
Muddy m = new Muddy();
long end = System.currentTimeMillis() - st;
System.out.println(end);
}
}
Then I executed this little batch script to measure it 100 times and put the values in a file. batchFile.bat First Second dum.res.txt
After that, I wrote this piece of code to calculate mean value and standard deviation of Dummy's and Muddy's measured values.
This is the result that I've got:
First size: 100 Second size: 100
First Sum: 132 Std. deviation: 13
Second Sum: 112 Std. deviation: 9
And it is similar on my other machines...every time I test it.
Now I'm wondering, why is it so? I checked the bytecode and Second.class has one instruction more (call to static initList()) between calls to System.currentTimeMillis().
They both do the same thing, but why is the First one slower? I can't really reason it out just by looking at the bytecode, since this was my first time touching javap; I don't understand bytecode yet.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为静态块版本比静态方法版本慢的原因可能是由于它们获得了不同的 JIT 优化......
请参阅这篇有趣的文章以获取更多有趣的信息:Java Secret:静态块是否被解释?
I think that the reason why the static block version is slower than the static method version could be due to the different JIT optimization that they get ...
See this interesting article for more interesting information : Java Secret: Are static blocks interpreted?
我对此原因的猜测是:
您正在执行的初始化正在创建足够的对象,从而导致一个或多个垃圾收集。
当从静态块调用初始化时,它是在类初始化期间完成的,而不是在简单方法执行期间完成的。在类初始化期间,垃圾检测器可能比简单方法执行期间有更多的工作要做(例如,因为执行堆栈更长),即使堆的内容几乎相同。
要测试这一点,您可以尝试在 java 命令中添加 -Xms200m 或其他内容;这应该消除在您正在进行的初始化期间进行垃圾收集的需要。
Here's my guess as to the reason for this:
The initialization you are doing is creating enough objects that it is causing one or more garbage collections.
When the initialization is called from the static block, it is done during the class initialization rather than during simple method execution. During class initialization, the garbage detector may have a little more work to do (because the execution stack is longer, for example) than during simple method execution, even though the contents of the heap are almost the same.
To test this, you could try adding -Xms200m or something to your java commands; this should eliminate the need to garbage collect during the initialization you are doing.