使用Java分析器优化代码性能,解决OOM问题

有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top

首发博客地址


背景

最近我一直在做性能优化,对一个单机应用做性能优化。主要是涉及到解析和导入导出相关的业务。

大致说一下这个单机应用干嘛的:制作票样,类似于答题卡。发给某些人填写,然后通过单机python图像识别存到数据库里面,在我们单机平台进行各种分析汇总数据。

前面呢已经优化了两块,一个是解析(目前性能提升了8倍,后续再优化),一个是汇总(性能提升了10倍+,后续再优化)。

写这个呢是因为有个服务在大数据量的时候总是OOM,实在是头疼呀,只能搞内存分析了,做内存分析有很多主要软件。。我这里呢不折腾,就用Idea自带的,个人觉得宇宙无敌啊。

实际业务呢,是需要实现一个功能,一键换机。我的实现思路呢是通过导出sql文件,然后另一台机子导入sql文件。

这里数据量实在是太大,主要是图片数据太大,因为历史表设计问题,所以图片是直接存储到数据库的。

我们是一个批次为一组,一个批次下面有多家单位,一个单位下面可能会有数千条数据,每条数据都有一张图片,大部分图片大小在200k左右。

另一个受限点是,实际运行程序的单机内存只有4g的样子,非常小。

一家单位导出来的数据量大概是2个多G

如何使用

在试图>工具窗口下面有一个分析器,点开它

如果你的idea没有该功能,请升级最新版

使用Java分析器优化代码性能,解决OOM问题_第1张图片

然后我们正常启动项目

项目起来后,这边会刷出启动的进程,然后我们需要附加Profile

使用Java分析器优化代码性能,解决OOM问题_第2张图片

这里显示正在分析那就没问题了,我们去网站上执行导出操作

使用Java分析器优化代码性能,解决OOM问题_第3张图片

实时查看CPU和堆内存

这里能看到这种情况是因为,我优化了一下,在每次处理完之后就手动GC一下,如果不手动GC大概处理三轮就OOM了

这个也是我已经优化后的一种手段,后续我打算调高每次批量处理的阈值,提高单次处理效率

使用Java分析器优化代码性能,解决OOM问题_第4张图片

我们点击停止分析,就能看到下面的页面

分析结果

火焰图

火焰图(Flame graph)是一种可视化工具,用于分析和优化软件的性能。它以图形的形式展示了程序在执行过程中各个函数的调用关系和耗时情况。

火焰图的横轴表示程序的执行时间,纵轴表示函数调用栈。每个函数在火焰图中以一个矩形表示,矩形的宽度表示函数在执行过程中所占用的时间比例,矩形的高度表示函数的调用深度。通过火焰图,我们可以直观地看到程序中哪些函数占用了大量的时间,从而帮助我们找到性能瓶颈和优化的方向。

要生成火焰图,通常需要使用性能分析工具来采集程序的执行数据。常用的性能分析工具包括Linux下的perf、Java应用程序中的Java Flight Recorder(JFR)和Java VisualVM等。这些工具可以记录程序的函数调用信息和耗时情况,并生成火焰图。

生成火焰图后,我们可以通过观察火焰图中的热点函数(即占用时间较多的函数)来进行性能优化。可以考虑对热点函数进行代码优化、算法优化、并发优化等,以提高程序的性能和响应速度。

使用Java分析器优化代码性能,解决OOM问题_第5张图片

调用树

调用树(Call Tree)是一种可视化工具,用于展示程序在执行过程中函数之间的调用关系。它以树状结构的形式展示了函数的调用层次和调用次数。 在调用树中,根节点表示程序的入口函数,每个子节点表示一个被调用的函数。通过观察调用树,我们可以了解函数之间的调用流程,找到函数的调用路径和调用次数,从而帮助我们分析程序的执行逻辑和性能瓶颈。 调用树通常会显示每个函数的调用次数和总耗时。这样我们可以快速识别出调用次数较多或耗时较长的函数,从而找到可能的性能问题和优化的方向。

使用Java分析器优化代码性能,解决OOM问题_第6张图片

方法列表

使用Java分析器优化代码性能,解决OOM问题_第7张图片

时间线

使用Java分析器优化代码性能,解决OOM问题_第8张图片

事件

使用Java分析器优化代码性能,解决OOM问题_第9张图片

分析

这些图吧,看着也不麻烦,揣摩下也大概能知道干嘛的,我举个例子

在调用树视图中,我们一直点下去,看到下面这个方法,占用了33.8%时间啊,这不得赶紧优化一下

使用Java分析器优化代码性能,解决OOM问题_第10张图片
    private String bytesToHexString(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

那我后面就把这块代码重构下就行,优化过程大致就是这样啦,大家掌握方法就好

后记

如果你想了解使用Xrebel优化接口性能,可以看看这篇文章:http://blog.zysicyj.top/db82e5f2 我前两天写了优化解析接口性能的,可以看看这篇文章:http://blog.zysicyj.top/a384b09f

本文由 mdnice 多平台发布

你可能感兴趣的:(后端)