测量Java应用程序的性能
我正在处理一份至少有15年历史的申请。我正在努力提高一个特定流的性能,这个流有大约10K行代码。此流程涉及向外部系统发送有关JMS主题的信息。我在创建和缓存会话的过程中发现了一些问题,在解决这些问题后,我已经能够节省一些时间。现在我想进一步提高性能。为此,我需要遍历整个10K代码行,并确定在哪些方面可以节省时间。该流程分为三个部分: 第一部分创建单个请求的批处理并执行一些操作(线程池大小为15) 第二部分从第一部分获取输入并进行更多的处理(10个线程的线程池) 第三部分从第二部分获取输入并进行更多的处理(10个线程的线程池) 我不能增加线程的数量,因为资源是有限的,这不是应用程序中的唯一流(我的配置是-2个套接字,每个套接字12个核心,每个核心2个线程)。此外,我没有太多的自由来处理这个问题,因为这些第一、第二和第三部分也在其他地方使用 为了确定执行时间,我创建了一个带有一个threadlocal变量的类,该变量包含日志语句,下面是代码:测量Java应用程序的性能,java,performance,Java,Performance,我正在处理一份至少有15年历史的申请。我正在努力提高一个特定流的性能,这个流有大约10K行代码。此流程涉及向外部系统发送有关JMS主题的信息。我在创建和缓存会话的过程中发现了一些问题,在解决这些问题后,我已经能够节省一些时间。现在我想进一步提高性能。为此,我需要遍历整个10K代码行,并确定在哪些方面可以节省时间。该流程分为三个部分: 第一部分创建单个请求的批处理并执行一些操作(线程池大小为15) 第二部分从第一部分获取输入并进行更多的处理(10个线程的线程池) 第三部分从第二部分获取输入并进行更
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的帮助