一:背景

1. 讲故事

只要是程序总会出现各种莫名其妙的问题,比如:非托管内存泄露,程序崩溃,在 Windows 平台上一般用微软自家的官方工具 App Verifier 就可以洞察,那问题出在 Linux 上怎么办呢?由于 Linux 崇尚自由,需要在各种牛鬼蛇神写的非官方开源软件中寻找一个比较靠谱的,比如本篇所说的 Valgrind

个人感觉 ValgrindApp Verifer 定位是差不多的,技术上前者使用 hook 钩子,后者使用仿真cpu,有点像 windbg 的 TTD 调试,具体信息参考:https://valgrind.org/

二:Valgrind 内存洞察

1. 安装

如果你用的是 ubuntu,可以用 apt-get 直接安装,方便快捷,目前最新的版本是 3.15.0


root@skyfly-virtual-machine:/home/skyfly/Desktop# apt-get install valgrind
Reading package lists... Done
Building dependency tree
Reading state information... Done
valgrind is already the newest version (1:3.15.0-1ubuntu9.1).
0 upgraded, 0 newly installed, 0 to remove and 23 not upgraded. root@skyfly-virtual-machine:/home/skyfly/Desktop# valgrind --version
valgrind-3.15.0

2. 内存泄露洞察

内存泄露大多是 new/delete , malloc/free 不匹配造成的,接下来写一个不匹配的 malloc/free 观察下。


#include <iostream>
#include <stdio.h> using namespace std; int main(void)
{
int *p = (int *)malloc(4);
*p = 10; printf("p=%d", *p); return EXIT_SUCCESS;
}

这里使用 vscode 进行编译,怎么编译就不说了,参见上一篇,接下来用 algrind --leak-check=full ./main.out 以仿真的方式把程序跑起来,截图如下:

从图中的 HEAP SUMMARY 区域可以看到,当前有 3 个 malloc,但只有 2 个 free,而且还找到了那个没有 free 的 malloc,在代码的 main.cpp:8 行,即 int *p = (int *)malloc(4); 处。

3. 栈溢出洞察

相信经常写递归的朋友总会遇到这类问题,为了方便演示,我故意实现一个 栈上溢 的例子吧。


#include <iostream>
#include <stdio.h> using namespace std; int main(void)
{
int num = 10;
int *ptr = &num; ptr -= 0x40;
*ptr = 15; return EXIT_SUCCESS;
}

从图中可以清晰的看到,主线程栈上的地址 0x1ffefffd5c 无法写入,还指出了在 main.cpp:12 行,即 *ptr = 15; 处。

为了方便验证,这里用 g++ 调试的方式洞察一下。


-exec p num
$5 = 10 -exec x ptr
0x7fffffffde2c: 0xf7fb0e9800007fff -exec info reg
...
rbp 0x7fffffffdf40 0x7fffffffdf40
rsp 0x7fffffffdf20 0x7fffffffdf20
...

从输出看,ptr 已经逃出了 rsp ~ rbp 范围之内,很明显上溢了,如果用 x 命令观察的话,可以看到里面的内容就很随机,在 windbg 中用以 ??? 来表示的。


-exec x ptr
0x7fffffffde2c: 0xf7fb0e9800007fff -exec x 0xf7fb0e9800007fff
0xf7fb0e9800007fff: Cannot access memory at address 0xf7fb0e9800007fff

除了观察 rsp,rbp,还可以看虚拟地址中的 stack 空间。


-exec i proc mapping
process 8327
Mapped address spaces: Start Addr End Addr Size Offset objfile
...
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x2d000 /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack]

4. 数组越界洞察

valgrind 这玩意也有弱鸡的时候,比如数组越界之类的问题它就搞不定,比如下面的代码:


#include <iostream>
#include <stdio.h> using namespace std; int main(void)
{
int num[5] = {1, 2, 3, 4, 5};
int num2[10]; num[6] = 15; return EXIT_SUCCESS;
}

通过下面的汇编代码观察,可以看到目前分配了 0x30 = 0n48 byte 的栈空间,截图如下:

虽然 num[6] 是越界操作,但是在合理的 栈空间 内,这种仿生cpu的方式洞察不出来,App Verifier 这种 hook 的方式是没有问题的。

接下来用 valgrind 尝试一下,可以看到果然没发现任何问题,输出如下:


skyfly@skyfly-virtual-machine:~/code$ valgrind ./main.out
==10244== Memcheck, a memory error detector
==10244== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10244== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==10244== Command: ./main.out
==10244==
==10244==
==10244== HEAP SUMMARY:
==10244== in use at exit: 0 bytes in 0 blocks
==10244== total heap usage: 1 allocs, 1 frees, 72,704 bytes allocated
==10244==
==10244== All heap blocks were freed -- no leaks are possible
==10244==
==10244== For lists of detected and suppressed errors, rerun with: -s
==10244== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

三:总结

总的来说,Valgrind 在洞察内存方面还是非常强大的,但也有它不能触及到的地方,熟悉它的优点和缺点,全面了解对我们调试师来说至关重要,希望本篇对你有帮助。

聊一聊 Valgrind 监视非托管内存泄露和崩溃的更多相关文章

  1. 记一次 .NET 某电子厂OA系统 非托管内存泄露分析

    一:背景 1.讲故事 这周有个朋友找到我,说他的程序出现了内存缓慢增长,没有回头的趋势,让我帮忙看下到底怎么回事,据朋友说这个问题已经困扰他快一周了,还是没能找到最终的问题,看样子这个问题比较刁钻,不 ...

  2. 记一次 .NET 某智慧水厂API 非托管内存泄漏分析

    一:背景 1. 讲故事 七月底的时候有位朋友在wx上找到我,说他的程序内存占用8G,托管才占用1.5G,询问剩下的内存哪里去了?截图如下: 从求助内容看,这位朋友真的太客气了,动不动就谈钱,真伤感情, ...

  3. VB.NET 内存指针和非托管内存的应用

    介绍 Visual Basic 从来不像在C或C++里一样灵活的操纵指针和原始内存.然而利用.NET框架中的structures 和 classes,可以做许多类似的事情.它们包括 IntPtr,   ...

  4. C# 托管内存与非托管内存之间的转换

    c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存 ...

  5. 如何让IntPtr指向一块内存,以及托管内存与非托管内存的相互转化

    IntPtr idp= IntPtr.Zero; StringBuilder idata = new StringBuilder("000000"); string idata = ...

  6. C# 中托管内存与非托管内存之间的转换

    c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存 ...

  7. 记一次 .NET 某打印服务 非托管内存泄漏分析

    一:背景 1. 讲故事 前段时间有位朋友在微信上找到我,说他的程序出现了内存泄漏,能不能帮他看一下,这个问题还是比较经典的,加上好久没上非托管方面的东西了,这篇就和大家分享一下,话不多说,上 WinD ...

  8. vld,Bounds Checker,memwatch,mtrace,valgrind,debug_new几种内存泄露检测工具的比较,Valgrind Cheatsheet

    概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却 ...

  9. 记一次 .NET 某桌面奇侠游戏 非托管内存泄漏分析

    一:背景 1. 讲故事 说实话,这篇dump我本来是不准备上一篇文章来解读的,但它有两点深深的感动了我. 无数次的听说用 Unity 可做游戏开发,但百闻不如一见. 游戏中有很多金庸武侠小说才有的名字 ...

  10. C# 非托管内存使用时的注意事项

    调用Marshal.AllocHGlobal必须调用 Marshal.FreeHGlobal(ptr)来手动释放内存,即使调用GC.Collect();方法也无法释放,导致内存泄露!!

随机推荐

  1. mysql 设置查询超时配置

    mysql设置查询超时 mysql5.6: max_statement_time (毫秒) mysql5.7: max_execution_time(毫秒) mariadb: max_statemen ...

  2. 需求分析之道——需求分析要做什么(C系架构设计法,sishuok)

    需求分析之道--需求分析要做什么. 需求分析是架构师开始做架构设计的第一步,对架构师来讲非常非常的重要.因为需求分析能够告诉我们,到底我们要做什么,架构设计就是为了去完成这件事情而做的. 接下来,我们 ...

  3. FinOps首次超越安全成为企业头等大事丨云计算趋势报告

    随着云计算在过去十年中的广泛应用,云计算用户所面临的一个持续不变的趋势是:安全一直是用户面临的首要挑战.然而,这种情况正在发生转变. 知名IT软件企业 Flexera 对云计算决策者进行年度调研已经持 ...

  4. c/c++指针从浅入深介绍——基于数据内存分配的理解(上)

    c/c++指针从浅入深介绍--基于数据内存分配的理解(上) 本文是对自我学习的一个总结以及回顾,文章内容主要是针对代码中的数据在内存中的存储情况以及存储中数值的变化来对指针进行介绍,是对指针以及数据在 ...

  5. 4.错误代码C1083

    有的时候在VS中遇到的error C1083: 无法打开**: " * .*": No such file or directory的错误,这里总结了我遇到过的情况: 错误 C10 ...

  6. graphviz 简单入门

    上一位负责画图的选手 CS Academy 由于不明原因暂时不能继续工作,所以本俱乐部招收了新选手 graphviz. 在 Linux 上,你可以这么下载: sudo apt install grap ...

  7. Mybatisplus----DML编程控制

    乐观锁 (1)业务并发现象带来的问题:秒杀 执行: 1.在类对象中添加version属性,在数据库表中添加version字段(默认值为1) package com.itheima.domain; im ...

  8. Python——基础知识(一)

    1. 那么多编程语言,为什么学python 易于学习,是所有编程语言当中最容易学习的 没有最好的语言,只有最合适的语言 2. 反复执行的用例如何提升效率 测试流程回归(回顾) 很多测试用例在不同的测试 ...

  9. StyleGAN 调整面部表情,让虚拟人脸更生动

    目录 人脸表情 调整步骤 调整结果 人脸表情 通过上一篇文章 StyleGAN 生成的人脸:https://www.cnblogs.com/tinygeeker/p/17236264.html 人脸图 ...

  10. 获取JSON数据_获取二进制数据

    #百度jk图片 import requests # 请求头 header={"user-agent": "Mozilla/5.0 (Windows NT 10.0; WO ...