测量Java应用程序的性能

测量Java应用程序的性能,java,performance,Java,Performance,我正在处理一份至少有15年历史的申请。我正在努力提高一个特定流的性能,这个流有大约10K行代码。此流程涉及向外部系统发送有关JMS主题的信息。我在创建和缓存会话的过程中发现了一些问题,在解决这些问题后,我已经能够节省一些时间。现在我想进一步提高性能。为此,我需要遍历整个10K代码行,并确定在哪些方面可以节省时间。该流程分为三个部分: 第一部分创建单个请求的批处理并执行一些操作(线程池大小为15) 第二部分从第一部分获取输入并进行更多的处理(10个线程的线程池) 第三部分从第二部分获取输入并进行更

我正在处理一份至少有15年历史的申请。我正在努力提高一个特定流的性能,这个流有大约10K行代码。此流程涉及向外部系统发送有关JMS主题的信息。我在创建和缓存会话的过程中发现了一些问题,在解决这些问题后,我已经能够节省一些时间。现在我想进一步提高性能。为此,我需要遍历整个10K代码行,并确定在哪些方面可以节省时间。该流程分为三个部分: 第一部分创建单个请求的批处理并执行一些操作(线程池大小为15) 第二部分从第一部分获取输入并进行更多的处理(10个线程的线程池) 第三部分从第二部分获取输入并进行更多的处理(10个线程的线程池)

我不能增加线程的数量,因为资源是有限的,这不是应用程序中的唯一流(我的配置是-2个套接字,每个套接字12个核心,每个核心2个线程)。此外,我没有太多的自由来处理这个问题,因为这些第一、第二和第三部分也在其他地方使用

为了确定执行时间,我创建了一个带有一个threadlocal变量的类,该变量包含日志语句,下面是代码:

public class ExecutionTraceManager {

private static Category cat = Category.getInstance(ExecutionTraceManager.class.getCanonicalName());

private static final ThreadLocal<Tracer> traceContainer = new ThreadLocal<Tracer>() {
    @Override
    protected Tracer initialValue() {
        return new ExecutionTraceManager().new Tracer();
    }
};

public static void addTrace(String trace) {
    traceContainer.get().addTrace(trace);
}

public static void printTrace(){
    ArrayList<String> trace = traceContainer.get().trace;
    StringBuffer buffer = new StringBuffer();
    for(String current : trace){
        buffer.append(current).append("\n");
    }

    cat.info(buffer);
}

public class Tracer {
    ArrayList<String> trace = new ArrayList<String>();
    long startTime = System.nanoTime();
    boolean init = false;
    public void addTrace(String traceMessage) {
        if(!init){
            startTime = System.nanoTime();
            init = true;
        }
        StringBuffer buffer = new StringBuffer("Time taken till [ ")
                .append(traceMessage)
                .append(" ] is : "
                        + ((System.nanoTime() - startTime) / 1000000.0));
        trace.add(buffer.toString());
    }
}
公共类ExecutionTraceManager{
私有静态类别cat=Category.getInstance(ExecutionTraceManager.class.getCanonicalName());
私有静态最终ThreadLocal traceContainer=新ThreadLocal(){
@凌驾
受保护的跟踪程序初始值(){
返回新的ExecutionTraceManager();
}
};
公共静态void addTrace(字符串跟踪){
traceContainer.get().addTrace(跟踪);
}
公共静态void printTrace(){
ArrayList trace=traceContainer.get().trace;
StringBuffer=新的StringBuffer();
用于(字符串当前:跟踪){
buffer.append(当前).append(“\n”);
}
类别信息(缓冲区);
}
公共类跟踪器{
ArrayList跟踪=新的ArrayList();
long startTime=System.nanoTime();
布尔init=false;
公共void addTrace(字符串跟踪消息){
if(!init){
startTime=System.nanoTime();
init=真;
}
StringBuffer=新的StringBuffer(“到[”)所用的时间)
.append(traceMessage)
.append(“]是:”
+((System.nanoTime()-startTime)/1000000.0));
trace.add(buffer.toString());
}
}
在我的代码中,我只调用ExecutionTraceManager.addTrace,一旦线程完成任务,我就调用printTrace并将线程重置为本地线程,以便下次该线程处理下一个请求时,它会看到空的跟踪列表

这对我来说没问题,但我想了解识别哪些代码需要时间的其他方法(因为我有10行代码)。专业人士采取什么方法来处理此类问题。

使用度量集合库 在我看来,使用像这样的度量集合库是一个比自己滚动更好的解决方案,因为它处理采样,并具有各种度量实现(计时器、直方图等)。 基本上,您可以添加如下代码:

private final Timer responses = metrics.timer(name(RequestHandler.class, "responses"));

// in the method
    try (Timer.Context ctx = responses.time()) {
        // run operations
    }
}
这将生成执行时间的柱状图,您可以查询不同的百分位数(99、95、90等)。 它还有一个优势,即您可以在生产系统中运行它并收集度量

与探查器相比,我更喜欢这种方法,因为探查器往往会产生非常密集的输出,很难映射到应用程序的功能。 应用程序级别的计时度量生成更易于理解和执行的度量

使用分析器 尽管在生产环境中运行它需要付费许可证,但您也可以使用类似于“飞行记录器”中的探查器。
正如在其他答案中提到的,还有其他工具,如VisualVM,可以使用分析器。

使用JProfiler,简单易用


通过它运行JAVA程序,以测量各种函数的CPU使用率、内存使用率、垃圾收集等。

使用探查器。例如,VisualVM使用像yourkit这样的探查器并测量墙时间。感谢Stephen C,JVisualVM的帮助