首先回应一个网上的争议问题

就是对于Lambda能让Java程序慢30倍的一个一轮

首先说,Lambda/Stream为Java提供了强大的函数式编程,但是也有着对应的局限性

我们对于Lambda是否真正的比传统方法慢,需要进行基准测试,是源于源代码慢,还是编写层面上的,这就需要对应的的测试

对于Lambda,我们不能认为是一种语法糖,而是一种新的工作机制,初始化的时候,进行CallSite类的生成,这就导致需要在启动的时候占用内存

我们需要说一下基准测试的主要目的和特征

我们不能泛泛的说性能好或者块,我们需要利用基准测试,具体的,明确的进行测试,获得定量的,可重复数据了

对于Java,我们更加关注的基准测试,应该是微基准测试,微基准测试,一般是API级别的验证,和其他用例场景的对比

比如开发共享类库,为其他的模块提供服务

API对于性能有着特殊的要求,比如,实现定制的HTTP客户端,要求对HTTP服务器有着大量Get的吞吐请求

如何构建自己的微基准测试呢?

首先可以考虑使用JMH, OpenJDK自身就填充了大量使用JMH进行性能对比的接口,如果是做Java API级别的性能对比,JMH可以考虑

JMH由Hotspot JVM团队开发,支持完整的基准测试过程,预热,运行 统计 报告一个流程,支持Java和其他的JVM语言,针对Hotspot JVM 进行了各种优化,使用只需要引入Maven依赖

图片

JMH直接利用了注解,定义了具体的测试方式,以及基准测试详细配置,加上@Benchmark,可以说明是个基准测试的方法,在BenchmakrMode注解中,指定了基准测试模式,可以设置的有吞吐量 平均时间等模式

然后我们直接运行对应的jar即可

对于基准测试,我们需要注意的地方,就是能够覆盖我们的功能点吗?

以及避免JVM对一些代码进行特殊的优化,

对于JVM可能的优化,我们需要注意关闭,

首先JIT可能对代码进行本地机器码的优化,这就需要我们确保JIT已经对代码进行编译了

我们可以查看JIT编译后的信息

利用参数查看多久后进行了编译

-XX: +PrintCompilation

因为是基准测试,所以可能输入参数是固定的,而JVM可能对固定值进行优化,直接不执行

图片

比如mul是没有被使用的,所以导致这个method直接不被执行

而JMH可以保证代码的一定执行

比如BlackHole设施

public void testMethod(Blackhole blackhole) {

// …

blackhole.consume(mul);

}

还有State机制,避免常量被省略的问题

@State(Scope.Thread)

public static class MyState {

public int left = 10;

public int right = 100;

}

public void testMethod(MyState state, Blackhole blackhole) {

int left = state.left;

int right = state.right;

int mul = left * right;

blackhole.consume(mul);

}

JMH还有对State对象进行额外的处理,消除伪共享,标记@State,从而自动补齐

关于方法内联 Inlining对性能的影响,可以考虑打开如下的选项

-XX: +PrintInlining的选项

这就是一些微基准测试流程,而且对于GC的测试,可以考虑JDK11的 Epsilon GC

发表评论

邮箱地址不会被公开。 必填项已用*标注