
# 使用APM Profiler定位性能问题
APM Profiler 是一种持续性能剖析工具，可以帮助开发者准确找到应用程序中消耗资源最多的代码位置。
#### 前提条件
1. APM Agent 已接入，操作方法参见[增强型探针Java语言接入APM](https://support.huaweicloud.com/usermanual-apm2/apm_08_0021.html)。
2. Profiler功能已开启，操作方法参见[Profiler性能分析](https://support.huaweicloud.com/usermanual-apm2/apm_07_1027.html)。
 
#### 如何查询并解决CPU升高问题
1. 登录[APM控制台](https://auth.huaweicloud.com/authui/login.html?service=https://console.huaweicloud.com/console/#/login)。
2. 单击左侧![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543359927.png)，选择"管理与监管 \> 应用性能管理 APM"，进入APM服务页面。
3. 在左侧导航栏选择"应用监控 \>指标"，进入应用指标页。
4. 在界面左侧树单击待查看的基础监控环境后的![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511959978.png)。
5. 单击"基础监控"，切换至基础监控页签，监控项选择"JVM监控"。
6. 找到"cpu(%)"，发现CPU持续高达80%以上。
   
   图1cpu(%)   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511800006.png "点击放大")
   
   
7. 单击"Profiler性能分析"，切换至Profiler性能分析页签。
8. 单击"性能分析"，Profiler性能分析页面，类型选择"CPU Time"。 
   图2Profiler火焰图   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543399923.png "点击放大")
   
   
   
9. 分析火焰图数据，从火焰图中可以看到，java.util.LinkedList.node(int) 方法占用了 66% 的 CPU，而相应的业务代码方法是countPages(List)。 
   图3Profiler火焰图分析   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511800010.png "点击放大")
   
   
   
10. 分析业务代码，结合代码可以发现该方法countPages(List)是对入参集合list进行下标遍历，而通过火焰图运行时数据发现，传入的是LinkedList，而LinkedList底层数据结构是链表，通过下标遍历效率会非常差。 
    图4代码分析   
    ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543399927.png "点击放大")
    
    
    
11. 修复代码，将list的遍历算法从普通的下标for循环改为增强的for循环。 
    图5修复代码   
    ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511800012.png "点击放大")
    
    
    
12. 优化后，重复[步骤4]\~[步骤5]，发现CPU使用率\<1%。
    
    图6优化后CPU(%)   
    ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543399929.png "点击放大")
    
    
    
 
#### 如何查询并解决内存升高问题
前提条件：开启测试程序，同时设定heap的大小为2g(-Xms2g -Xmx2g)。
1. 在左侧导航栏选择"应用监控 \> 指标"。
2. 在界面左侧树单击待查看基础监控环境后的![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511966930.png)。
3. 单击"基础监控"，切换至基础监控页签，监控项选择"GC监控"。通过GC折线图发现，服务存在频繁的GC问题。
   
   图7查看GC监控   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543406867.png "点击放大")
   
   
4. 监控项选择"JVM监控"，查看JVM监控。 
   图8查看JVM监控   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511806946.png "点击放大")
   
   
5. 单击"Profiler性能分析"，切换至Profiler性能分析页签。
6. 单击"性能分析"，Profiler性能分析页面，实例选择"Allocated Memory"。根据右侧Self排序排查，找到分配内存最多的方法。
   
   图9内存火焰图   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543366883.png "点击放大")
   
   
   
7. 查看代码，发现LargeEnum是个枚举类，定义了大量的常量。由于枚举类的方法values()底层是通过数组clone实现的，即每次调用values()方法，底层会复制一个枚举数组，所以会导致频繁分配堆内存，频繁GC。 
   图10查看代码   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543406869.png "点击放大")
   
   
   
8. 问题修复，将values定义为一个常量，避免频繁调用enum.values()。 
   图11问题修复   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543366885.png "点击放大")
   
   
   
9. 重复[步骤3]\~[步骤6]，发现GC次数大幅下降，并且火焰图中找不到enum.values()内存分配。
   
   图12优化后GC监控   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543406871.png "点击放大")
   图13优化后性能分析火焰图   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511806950.png "点击放大")
   
   
   
 
#### 如何查询并解决接口响应慢问题
1. 在左侧导航栏选择"应用监控 \> 指标"。
2. 在界面左侧树单击待查看基础监控环境后的![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511966936.png)。
3. 单击"接口调用"，切换至接口调用页签。通过APM的接口调用功能发现接口响应慢，平均响应时间80s左右。 
   图14接口调用   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002543406873.png "点击放大")
   
   
4. 单击"Profiler性能分析"，切换至Profiler性能分析页签。
5. 单击"性能分析"，Profiler性能分析页面，实例选择"Latency", 输入接口所在的方法。 
   图15性能分析   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511806952.png "点击放大")
   
   
   
6. 排查调用栈，寻找耗时的方法。如下图，NegativeWorkService#handle中executeUpdate()方法耗时最多。 
   图16排查调用栈   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511966938.png "点击放大")
   
   
   
7. 排查NegativeWorkService#handle方法，发现根因是循环内执行数据库插入操作。 
   图17排查NegativeWorkService#handle方法   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511806954.png "点击放大")
   
   
   
8. 问题修复，改为批量插入数据。 
   图18问题修复   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511966940.png "点击放大")
   
   
   
9. 观察接口调用平均响应时间，从80s减少到0.2s。 
   图19优化后查询接口调用平均响应时间   
   ![](https://support.huaweicloud.com/bestpractice-apm2/zh-cn_image_0000002511806956.png "点击放大")
   
   
 
