C++服务内存分析

1 查看进程内存常用命令

1.1 ps

ps -aux | grep redis

root      260337  0.0  0.1  68836 11640 ?        Ssl   2023 444:56 redis-server *:6380 [cluster]
root      260343  0.0  0.1  68476 11284 ?        Ssl   2023 440:08 redis-server *:6381 [cluster]

1.2 top

top -p $pid

Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.3 us,  1.3 sy,  0.0 ni, 95.7 id,  0.5 wa,  0.0 hi,  0.2 si,  0.0 st
MiB Mem :   7768.7 total,    259.9 free,   4510.2 used,   2998.6 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   2959.8 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                                                                                                                 
 260337 root      20   0   68836  11640   3048 S   0.0   0.1 444:56.89 redis-server 

1.3 pidstat

pidstat -p $pid 1 -r:每隔1秒输出依次进程的内存使用情况

Linux 4.18.0-305.3.1.el8.x86_64 (VM-32-17-centos)       2024年03月26日  _x86_64_        (2 CPU)
22时24分01秒   UID       PID  minflt/s  majflt/s     VSZ     RSS   %MEM  Command
22时24分02秒     0    260337      0.00      0.00   68836   11640   0.15  redis-server
22时24分03秒     0    260337      0.00      0.00   68836   11640   0.15  redis-server
22时24分04秒     0    260337      0.00      0.00   68836   11640   0.15  redis-server

2 详细的内存分布

2.1 valgrind massif

vrlgrind 提供了一种分析内存的工具massif,可以帮助我们分析进程的内存占用情况和变化趋势。massif

如何使用

例如我得程序名称为 demo, 启动方式为: ./bin/demo conf.json,那么我们可以通过下面两个步骤产出内存分析报告:

  1. 使用massif启动进程并开始对内存进行分析
    valgrind -v --tool=massif --detailed-freq=10 --depth=10 --threshold=1 --massif-out-file=./massif.out ./bin/demo conf.json
    启动后工具会对内存进行快照,每10个快照生成一次详细的分析,分析树中最大深度为10,内存占比小于1%的部分不在分析树中进行展示。之后,我们终止分析,会生成massif.out文件。
  2. ms_print massif.out 输出分析报告

输出报告怎么看

  1. 报告开始的地方会给出进程的一些信息和一个内存的统计图
--------------------------------------------------------------------------------
Command:            ./bin/demo  conf.json
Massif arguments:   (none)
ms_print arguments: massif.out
--------------------------------------------------------------------------------
    GB
25.66^                                                                       :
     |                                                                       #
     |                                                                       #
     |                                                                       #
     |                                                                       #
     |                                                                    ::@#
     |                              @@:::::::@:@:::::::::::::::::@::::::::: @#
     |                          ::::@ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |                   @::::::: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |                  @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |               :::@@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |               :: @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |             :::: @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |          :::: :: @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |       @@@: :: :: @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |     ::@ @: :: :: @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |    @: @ @: :: :: @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     |  @@@: @ @: :: :: @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     | @@ @: @ @: :: :: @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
     | @@ @: @ @: :: :: @@:: : :: : @ :: :: :@:@: : : :: :  ::: :@: :: :: : @#
   0 +----------------------------------------------------------------------->Ti
     0                                                                   2.065

Number of snapshots: 75
 Detailed snapshots: [1, 2, 3, 5, 6, 12, 13, 22, 28, 30, 41, 48, 54, 64, 68, 69, 70, 71 (peak)]

起始的表格是记录一些启动参数。接着是一个统计图, 图的纵轴是内存大小,例如上图是GB为单位,横轴的单位默认是指令数,可以通过–time-unit选项设置为ms(时间,毫秒为单位,如果进程执行时间很短,为了清晰看到中间环节,可以使用该选项), B(内存分配大小)。图中由三类符号:

  • : 表示快照是一次普通快照,只记录大概信息
  • @ 表示一次详细的快照,会输出内存占用的详细信息
  • # 表示内存峰值的一次快照。

Number of snapshots: 表示工具总共进行多少次内存快照
Detailed snapshots:表示哪些快照是保存的详细信息

  1. 普通快照信息
    记录总共申请了多少内存, 使用了多少内存,已经因为内存对齐和head信息额外申请的内存大小。
    total=useful-heap+extra-heap (没有记录栈空间的情况下)
--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
  4 185,986,340,777   16,683,855,416   15,855,594,450   828,260,966            0
  1. 详细快照信息
    下面的内容是我手动精简之后的,避免太多内容影响查看。可以看到第5次块为详细快照,记录了每一部分内存主要消耗在哪里。例如,下图中,总共占用了17.6G内存,其中19.89%是低于1%阈值的,没有记录。15.16%来自 CAhoCorasick::initialize() 这个函数,该函数由loaddata调用。 这样我们便能够轻松的定位到到底是哪些函数的哪些操作占用了较多的内存,方便进一步的针对性优化。
  5 231,717,477,787   18,627,986,072   17,621,534,931 1,006,451,141            0
94.60% (17,621,534,931B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->19.89% (3,705,401,934B) in 1580 places, all below massif's threshold (1.00%)
| 
->15.16% (2,824,867,416B) 0xA5DA1F7: CAhoCorasick::initialize(int, int const*, char const**) (in /usr/lib64/xx.so.0.0.0)
| ->08.11% (1,510,635,112B) 0x6D7ED50: loaddata(char const*) (xx.cpp:28)
| | ->08.11% (1,510,635,112B) 0x6DC6D2D: operator() (xx.cpp:1177)       
| ->07.06% (1,314,232,304B) 0x5A910A: loadDict(char const*) (yy.cpp:29)
|         
->14.38% (2,679,624,312B) 0x16DCDE5C: re_node_set_merge (in /usr/lib64/libc-2.17.so)
| ->14.38% (2,679,624,312B) 0x16DDA7B4: calc_eclosure_iter (in /usr/lib64/libc-2.17.so)
|
->08.95% (1,666,926,376B) 0x16DDE339: re_compile_internal (in /usr/lib64/libc-2.17.so)
| ->08.95% (1,666,926,376B) 0x16DDF36F: regcomp (in /usr/lib64/libc-2.17.so)
|   ->08.37% (1,558,788,552B) 0x6EAE61C: InitJob(char const*) (a.cpp:4513)
|   | ->08.37% (1,558,788,552B) 0x6EAF1B2: InitRules(char const*) (a.cpp:229)
|   
->07.85% (1,461,641,324B) 0x1659CA18: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
| ->02.74% (509,998,183B) 0xC6DE2E0: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib64/libboost_regex.so.1.53.0)
| | ->02.25% (418,530,522B) 0x1659E6D7: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)                         

一些重要的options

–max-snapshots: 最大快照数,超出这个数目会将前面的记录进行删除
–main-stacksize: 指定main线程的栈空间大小
–depth : 内存分析树的深度,默认是30
–threshold: 小于该阈值时,分析树上不在进行记录,默认是1.0, 即1%
–detailed-freq: 记录快照的频率,默认10,即每生成10次内存快照记录一次详细快照
–massif-out-file: 指定输出的记录文件位置

2.2 jeprof

相关推荐

  1. C++服务内存分析

    2024-03-27 13:44:03       39 阅读
  2. C++内存分区

    2024-03-27 13:44:03       53 阅读
  3. C++之内存分区

    2024-03-27 13:44:03       43 阅读
  4. 6. C++ 内存分布

    2024-03-27 13:44:03       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-27 13:44:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-27 13:44:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-03-27 13:44:03       82 阅读
  4. Python语言-面向对象

    2024-03-27 13:44:03       91 阅读

热门阅读

  1. STEVE - Voracious Steve dfs , 以及为什么不能博弈

    2024-03-27 13:44:03       43 阅读
  2. nginx负载均衡模式

    2024-03-27 13:44:03       41 阅读
  3. 能否把 Redis 当做消息队列来用呢?

    2024-03-27 13:44:03       44 阅读
  4. Python的异常处理

    2024-03-27 13:44:03       40 阅读
  5. Jenkins Docker 部署指南

    2024-03-27 13:44:03       42 阅读
  6. SpringBoot集成FreeMarker时访问不到.ftl文件

    2024-03-27 13:44:03       38 阅读
  7. 掌握Mac常用命令,提升工作效率

    2024-03-27 13:44:03       42 阅读
  8. Spring设计模式-实战篇之模板方法模式

    2024-03-27 13:44:03       44 阅读
  9. P8687 [蓝桥杯 2019 省 A] 糖果

    2024-03-27 13:44:03       40 阅读
  10. AI:143-基于深度学习的实时视频人物识别与跟踪

    2024-03-27 13:44:03       38 阅读