LINUX GDB: IDENTIFY MEMORY LEAKS(通过gdb脚本打印malloc和free)[通俗易懂]

LINUX GDB: IDENTIFY MEMORY LEAKS(通过gdb脚本打印malloc和free)[通俗易懂]下面为一种方法查找memory leak,但在实际使用过程中由于打印太多会导致效率很低,不是很实用,而且有些地方报错 如 *(malloc+191) 原文地址https://www.ibm.com/…

	LINUX GDB: IDENTIFY MEMORY LEAKS(通过gdb脚本打印malloc和free)[数据库教程]

下面为一种方法查找memory leak,但在实际使用过程中由于打印太多会导致效率很低,不是很实用,而且有些地方报错 如 *(malloc+191)

原文地址https://www.ibm.com/support/pages/linux-gdb-identify-memory-leaks

Abstract

LINUX GDB: IDENTIFY MEMORY LEAKS

Body

This small article describe how to track memory leaks using ‘gdb‘ on Linux. If you are using products like ‘db2‘ or any other product that has it‘s own memory management routines then you should first track possible leaks at the product level using the tools it provides. For ‘db2‘ that would be ‘db2pd‘ for example. This article therefore applies only to memory leaks at the ‘malloc()‘ level, that is blocks of memory allocated using ‘malloc()‘ but never freed.

 

Remember that a debugger is very slow and might cause performance issues. If you can ‘overload‘ the default ‘malloc()/free()‘ routines via LD_PRELOAD or another way it would probably be faster and easier than using the debugger.

 

NOTE: The ‘gdb‘ script provided below can be modified as fits. Remember that
      multiple things like ‘gdb‘ version, OS version, compilation options…
      can end up providing slightly different results and therefore you should
      consider this script more as a ‘basis‘ to work on rather than something
      that will work 100% on all platforms for whatever executable.

 

If you are still reading this means you have no other choice but using the debugger. So let‘s first describe what we need to do.

 

  – Everytime we enter ‘malloc()‘ we should ‘save‘ the memory allocation
    requested size in a variable.
  – Everytime we return from ‘malloc()‘ we should print the size and the
    return address from ‘malloc()‘.
  – Everytime we enter ‘free()‘ we should print the ‘pointer‘ we are
    about to free.

 

Note that while the ‘size‘ is not needed it is good to have it because it might allow you to find some ‘pattern‘ in the list of allocated blocks. Since we don‘t want to have to manually interact with the debugger each time a memory allocation is made or freed we want to put command in s script that gdb will take as an argument and execute without any manual intervention
required. Now let‘s show what the script looks like and then we will show a typical output and explain a few things about the script.

 

  == gdbcmd1 ==

  set pagination off
  set breakpoint pending on
  set logging file gdbcmd1.out
  set logging on
  hbreak malloc
  commands
  set $mallocsize = (unsigned long long) $rdi
  continue
  end
  hbreak *(malloc+191)
  commands
  printf “malloc(%lld) = 0x%016llx “, $mallocsize, $rax
  continue
  end
  hbreak free
  commands
  printf “free(0x%016llx) “, (unsigned long long) $rdi
  continue
  end
  continue

 

Then we attach a running process with the debugger using the script:

 

  # gdb –command=gdbcmd1 server2 11543

 

The program will run and send the output to a file named ‘gdbcmd1.out‘. Because the file contains as well ‘gdb‘ messages, besides the ‘printf‘ we added to the script we can get a clearer output by doing this:

 

  # grep -e “^malloc” -e “^free” gdbcmd1.out

 

We have something like this:

 

  malloc(57) = 0x0000000012e1b260
  free(0x0000000012e1b260)
  malloc(57) = 0x0000000012e1b260
  free(0x0000000012e1b260)
  malloc(100) = 0x000000000e497d30
  malloc(15) = 0x0000000011bda010
  malloc(568) = 0x0000000011bda030
  free(0x0000000000000000)
  malloc(2248) = 0x0000000011bda270
  free(0x0000000011bda030)
  malloc(20) = 0x0000000011bda030
  malloc(20) = 0x0000000011bda050
  malloc(20) = 0x0000000011bda070
  malloc(20) = 0x0000000011bda090
  malloc(20) = 0x0000000011bda0b0
  malloc(20) = 0x0000000011bda0d0
  free(0x0000000011bda010)
  malloc(15) = 0x0000000011bda010
  free(0x0000000011bda010)
  malloc(15) = 0x0000000011bda010
  malloc(21) = 0x0000000011bda210
  malloc(21) = 0x0000000011bda230
  malloc(56) = 0x0000000011bdafe0

 

Once you have that you can parse the output to find out those blocks that are never freed. Later on you can add a ‘where‘ command in the commands for the entry in ‘malloc()‘ breakpoint to see where the allocation comes from. So you would for example replace this:

 

  hbreak malloc
  commands
  set $mallocsize = (unsigned long long) $rdi
  continue
  end

 

By this:

 

  hbreak malloc
  commands
  set $mallocsize = (unsigned long long) $rdi
  where
  continue
  end

 

Now some words about the ‘gdb‘ script ‘gdmcmd1‘ itself:

 

  set pagination off

  – This prevents to have to press ‘return‘ each time the screen has been
    filled up with messages. This can be seen as some ‘auto-scroll‘ option.

 

  set breakpoint pending on

  – In case the library containing the function would not yet be loaded
    the debugger would wait for it before placing the breakpoint. In this
    case of course it should already be loaded in the running process.

 

  set logging file gdbcmd1.out

  – Instruct ‘gdb‘ to save the output to a file named ‘gdbcmd1‘.

 

  set logging on

  – Instruct ‘gdb‘ to start sending output to ‘gdbcmd1‘.

 

  hbreak malloc
  commands
  set $mallocsize = (unsigned long long) $rdi
  continue
  end

  – Place a ‘hardware assisted‘ breakpoint on the entry of malloc. Save the
    allocation requested size in a variable named ‘mallocsize‘. Note that on
    X86 AMD the first argument to a function is in register ‘$rdi‘.

 

  hbreak *(malloc+191)
  commands
  printf “malloc(%lld) = 0x%016llx “, $mallocsize, $rax
  continue
  end

  – Place a ‘hardware assisted‘ breakpoint on the return from malloc.
    Print the size as well as the pointer returned by malloc. Note that the
    return value on X86 AMD is in register ‘$rax‘. See below for finding
    the offset of the ‘return‘ instruction from malloc.

 

  hbreak free
  commands
  printf “free(0x%016llx) “, (unsigned long long) $rdi
  continue
  end
  continue

 

– Finding the ‘return‘ instruction offset from malloc –

 

We could use the ‘finish‘ instruction of ‘gdb‘ but in many cases it simply did not work as expected for me. So this way of doing it is an alternative. To find the return instruction offset in malloc you need to check the assembly for malloc (disas malloc in gdb) and locate the ‘retq‘ (64 bits) instruction. Then you take the address of that instruction and compute the offset starting from the first instruction in malloc. For example:

 

  (gdb) disas malloc
  Dump of assembler code for function malloc:
  0x0000003f8a673fb0 <malloc+0>:  mov    %rbp,-0x10(%rsp)
  0x0000003f8a673fb5 <malloc+5>:  mov    %rbx,-0x18(%rsp)
  0x0000003f8a673fba <malloc+10>: mov    %rdi,%rbp
  0x0000003f8a673fbd <malloc+13>: mov    %r12,-0x8(%rsp)
  0x0000003f8a673fc2 <malloc+18>: sub    $0x18,%rsp
  0x0000003f8a673fc6 <malloc+22>: mov    0x2dbe53(%rip),%rax
  0x0000003f8a673fcd <malloc+29>: mov    (%rax),%rax
  …
  0x0000003f8a674055 <malloc+165>:        mov    0x8(%rsp),%rbp
  0x0000003f8a67405a <malloc+170>:        mov    0x10(%rsp),%r12
  0x0000003f8a67405f <malloc+175>:        add    $0x18,%rsp
  0x0000003f8a674063 <malloc+179>:        retq
  0x0000003f8a674064 <malloc+180>:        mov    %rbx,%rdi
  0x0000003f8a674067 <malloc+183>:        mov    %rbp,%rsi
  0x0000003f8a67406a <malloc+186>:        xor    %r12d,%r12d
  …

  0x0000003f8a674063 – 0x0000003f8a673fb0 = 179

 

Once again you might have to play a bit with the script to obtain the results
you are after but this should give you a base to start on.

LINUX GDB: IDENTIFY MEMORY LEAKS(通过gdb脚本打印malloc和free)

原文地址:https://www.cnblogs.com/wangshaowei/p/14063608.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/6605.html

(0)
上一篇 2023-04-06
下一篇 2023-04-06

相关推荐

  • Postgresql 数据命令行导入导出操作「建议收藏」

    Postgresql 数据命令行导入导出操作「建议收藏」导入 COPY cnt_topholder_balance(datetime,chain,crypto,address,balance) FROM '/tmp/cnt_topholder_…

    2022-12-15
    143
  • 使用Python的break语句实现循环控制

    使用Python的break语句实现循环控制在Python中,break语句用于终止循环,从而实现循环控制。当遇到break语句时,程序将立即退出当前循环,跳转到最近的下一级语句,并继续执行。

    2024-01-31
    93
  • springboot 整合JDBC

    springboot 整合JDBC前提:配置数据库连接(见前面) 一、步骤 1、导包 org.springframework.boot spri…

    2023-03-27
    162
  • Redis | 第9章 Lua 脚本与排序《Redis设计与实现》[通俗易懂]

    Redis | 第9章 Lua 脚本与排序《Redis设计与实现》[通俗易懂](第9章 Lua 脚本与排序) 前言 参考资料:《Redis设计与实现 第二版》; 第三部分为独立功能的实现,主要由以下模块组成:发布订阅、事务、Lua 脚本、排序、二进制位数组、慢查询日志、监视器;

    2023-04-30
    145
  • 删除部分数据sql_sql删除数据语句

    删除部分数据sql_sql删除数据语句> 【SQL从一点一滴分析系列文章】为实际开发中的点点滴滴的总结,从最最简单的SQL 查询 到 综合分析查询 在分析 SQL 时,也会同时分析 mybatis 、Hibernate 中的相关操作 点…

    2023-01-31
    144
  • Python字母大小写转换

    Python字母大小写转换Python是一种很受欢迎的编程语言,在Python中有许多内置函数和方法可以用来操作字符串。字符串是Python中非常重要的一种数据类型,通常用来存储文本类型的数据。其中一种字符串操作是将字母的大小写转换,这是非常常见的操作。

    2024-08-21
    32
  • 如何更新pip

    如何更新pippip是Python包管理器,用于安装和升级Python模块和程序。更新pip是保持Python包最新和功能最佳的关键。在本文中,我们将探讨如何更新pip,让您的Python环境始终保持最新。

    2024-06-01
    66
  • 使用Python def定义函数

    使用Python def定义函数在Python编程中,函数是最基本的模块化组件。通过函数,我们可以将复杂的代码分解成更小的、可重复使用的代码块,有助于提高代码的可读性和可维护性。

    2024-09-20
    16

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注