关于性能:Java代码内部的基准测试

Benchmarking inside Java code

我最近一直在研究基准测试,我一直对记录程序数据等感兴趣。我想知道我们是否可以在程序中有效地实现自己的内存使用代码和实现自己的时间消耗代码。我知道如何检查代码运行所需的时间:

1
2
3
4
5
public static void main(String[]args){
        long start = System.currentTimeMillis();
        // code
        System.out.println(System.currentTimeMillis() - start);
    }

我还研究了健壮的Java标杆,第1部分:问题,本教程非常全面。显示System.currentTimeMillis();的负面影响。然后,本教程建议我们使用System.nanoTime();(使其更准确?).

我还研究了在Java中使用内存来确定内存使用情况。这个网站展示了你如何实现它。提供的代码看起来无效,因为该人员正在调用

long L = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

之后,他打了16次电话给System.gc();(4*4)=16次。然后再次重复这个过程。这不是也占用了记忆吗?

因此,在你的Java程序中,是否可能实现一个有效的标杆代码?


是的,可以有效地在Java代码中实现性能基准。重要的问题是,任何一种性能基准都会增加它自己的开销,以及你想要多少开销。system.currentmill..()是性能的足够好的基准,在大多数情况下,nanome()是一种过度杀伤力。

对于内存系统,gc将为不同的运行显示不同的结果(因为gc运行从未得到保证)。我通常使用VisualVM进行内存分析(它是免费的),然后使用TDA进行转储分析。

一种减少入侵的方法是使用面向方面的编程。您可以只创建一个在特定注释或方法集上运行的方面,并编写一个@around建议来收集性能数据。

下面是一个小片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TestAspect {

    @LogPerformance
    public void thisMethodNeedsToBeMonitored(){
        // Do Something
    }
    public void thisMethodNeedsToBeMonitoredToo(){
        // Do Something
    }
}

@interface LogPerformance{}

@Aspect
class PerformanceAspect{
    @Around("the pointcut expression to pick up all" +
           "the @PerfMonitor annotated methods")
    public void logPerformance(){
        // log performance here
        // Log it to a file
    }
}


如果没有一些海森堡效应,就不可能进行基准测试,也就是说,您的基准测试代码也会被测量。但是,如果您在足够高的粒度上进行测量,效果将可以忽略不计。


任何基准代码的效率都会比没有基准代码的效率低,这仅仅是基于有更多的事情要做。也就是说,JAVA特别是由于JRE感觉到垃圾收集时发生的问题而引起的。即使是system.gc的文档也表示它"尽了最大努力"。

关于您的具体问题:

system.gc不应该占用更多内存,但它将占用处理器资源。

这在某种程度上是有可能的,基于你正在尝试的基准。总会有一些干扰。如果你愿意走出你的代码,有像visualvm这样的工具可以从你的应用程序外部观察内存的使用。

编辑:更正system.gc文档所说的措辞。