C++内存分析工具

2023-10-27

C++ 内存分析工具

背景

​ 内存泄漏在c++中是一个常见的问题,有一个好用的内存分析工具就是很有必要的,下面来介绍两个简单好用的内存分析工具,Valgrind和Sanitizer;

Valgrind

valgrind是一种非侵入式的内存检测工具,在进行检查程序前不需要重新编译和连接;Memcheck会在错误发生时立即报告这些错误,给出发生错误的源行号,以及为到达该行而调用的函数的堆栈跟踪。Memcheck在字节级跟踪可寻址性,在位级跟踪值的初始化。因此,它可以检测单个未初始化位的使用,并且不会在位字段操作中报告虚假错误。Memcheck运行程序的速度比正常慢10-30倍。

工具的安装可以参考:Valgrind: Current Releases

主要包含一下集中标准的工具:

1. memcheck:内存错误检测器,检测内存问题,如内存泄漏,数组访问越界,非法指针等
2. callgrind:调用图缓存生成器,检测程序运行的时间和调用过程,用于分析性能,和Linux的perf工具类似
3. cachegrind:缓存和分支预测分析器;分析CPU缓存的命中率
4. heigrind:用于检测多线程中资源竞争问题;
5. massif:堆栈分析器,检测堆栈的hi使用使用情况;
主要介绍一下memcheck工具的的使用

原理:

通过维护两张表(valid-value和valid-address)来实现对运行程序的内存检查;

  • valid-value:记录整个进程地址空间的每个字节(每个字节对应8个bits位);CPU的每个寄存器同样有与之对应的bit向量;这些bit负责记录对应的字节或者寄存器中的值是否有效,是否已初始化;
  • valid-address:对整个进程地址空间的每个字节有一个与之对应的1bit,负责记该地址空间是否能够被读写;
  • 当要内存读写某个字节时,首先会检查valid-address表中的字节对应的那1bit值,判断字节所在地址时候有效,若发现时无效地址,memcheck会输出读写错误的报告;当内核要加载某个字节时,该字节对应在valid-value中的值也会加载到CPU内核中,当内核寄存器中的值被用来生产内存地址或者能影响程序的输出时,memcheck会检查该字节对应valid-value表中的值是否有效或者是否初始化,并给出对应的检测结果;

使用:

首先编译源代码时要加上 -g参数,保留调试信息,然后运行下面命令

valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./demo
  • –tool=memcheck:表示使用memcheck工具
  • –leak-check=full:表示显示每个泄漏的细节
  • –log-file=val_report:可以增加该参数,将分析结果生成日志,放到当前目录下的val_report文件中便于后续分析
例1 内存泄漏
#include <iostream>
using namespace std;
int main()
{
    int *p = new int(10);
    cout << "*p:" << *p << endl;
    //delete p;
    return 0;
}
==9543== Memcheck, a memory error detector
==9543== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==9543== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==9543== Command: ./demo
==9543== Parent PID: 8780
==9543== 
==9543== 
==9543== HEAP SUMMARY:
==9543==     in use at exit: 4 bytes in 1 blocks
==9543==   total heap usage: 3 allocs, 2 frees, 73,732 bytes allocated
==9543== 
==9543== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==9543==    at 0x4C2F87B: operator new(unsigned long) (vg_replace_malloc.c:434)
==9543==    by 0x4008E8: main (demo.cpp:5)
==9543== 
==9543== LEAK SUMMARY:
==9543==    definitely lost: 4 bytes in 1 blocks
==9543==    indirectly lost: 0 bytes in 0 blocks
==9543==      possibly lost: 0 bytes in 0 blocks
==9543==    still reachable: 0 bytes in 0 blocks
==9543==         suppressed: 0 bytes in 0 blocks
==9543== 
==9543== For lists of detected and suppressed errors, rerun with: -s
==9543== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

在输出的检测分析结果中,第1行已经指出存在一个内存检测错误;第8行给出具体的内存检测结果,共有4个字节的内存出现了泄漏;在demo.cpp文件的第5行出现该内存泄漏;第16行是将本次内存泄漏的所有情况进行汇总;主要专注前4类,具体含义如下:

  • definitely lost:确认存在内存泄漏;当程序结束时,存在动态申请的内存没有释放,且通过其他指针都无法正常访问该内存;
  • indirectly lost : 间接存在内存泄漏;当使用含有指针成员变量的类时可能会报该错误,一般都会与definitely lost同时存在,解决definitely lost问题,该问题随之消失;
  • possibly lost :可能存在内存泄漏;当程序结束时,存在动态申请的内存内有释放,且通过指针变量无法访问该内存的起始地址,但可以访问该内存中的后一部分数据;
  • still reachable:存在可以访问,未丢失但也未释放;若程序正常结束,虽然不会造成程序崩溃,但长时间的运行会消耗是系统内存资源,建议修复;若非正常结束,可忽略;
例2 使用已经释放的内存
#include <iostream>
using namespace std;
int main()
{
    int *p = new int(10);
    cout << "*p:" << *p << endl;
    delete p;
    int a = *p;
    return 0;
}

==10129== Memcheck, a memory error detector
==10129== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==10129== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==10129== Command: ./demo
==10129== 
*p:10
==10129== Invalid read of size 4
==10129==    at 0x40097F: main (demo.cpp:8)
==10129==  Address 0x5b1fc80 is 0 bytes inside a block of size 4 free'd
==10129==    at 0x4C31C86: operator delete(void*) (vg_replace_malloc.c:935)
==10129==    by 0x40097A: main (demo.cpp:7)
==10129==  Block was alloc'd at
==10129==    at 0x4C2F87B: operator new(unsigned long) (vg_replace_malloc.c:434)
==10129==    by 0x400938: main (demo.cpp:5)
==10129== 
==10129== 
==10129== HEAP SUMMARY:
==10129==     in use at exit: 0 bytes in 0 blocks
==10129==   total heap usage: 3 allocs, 3 frees, 73,732 bytes allocated
==10129== 
==10129== All heap blocks were freed -- no leaks are possible
==10129== 
==10129== For lists of detected and suppressed errors, rerun with: -s
==10129== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

结果分析的第7行指出,存在无效的读操作,发生在demo.cpp的第8行;该内存空间是在demo.cpp的第5行进行分配空间,在demo.cpp的第7行进行空间释放,在8行又去访问该内存;

例3 数组访问越界
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
    int *p1 = (int*)malloc(sizeof(int)*4);
    p1[4] = 10;
    free(p1);
    int *p2 = new int[4]{1,2,3,4};
    int c = p2[50];
    delete []p2;
    return 0;
}
==12822== Memcheck, a memory error detector
==12822== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==12822== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==12822== Command: ./demo
==12822== 
==12822== Invalid write of size 4
==12822==    at 0x4007F7: main (demo.cpp:7)
==12822==  Address 0x5b1fc90 is 0 bytes after a block of size 16 alloc'd
==12822==    at 0x4C2F15A: malloc (vg_replace_malloc.c:393)
==12822==    by 0x4007EA: main (demo.cpp:6)
==12822== 
==12822== Invalid read of size 4
==12822==    at 0x400845: main (demo.cpp:10)
==12822==  Address 0x5b1fd98 is 120 bytes inside an unallocated block of size 4,121,280 in arena "client"
==12822== 
==12822== 
==12822== HEAP SUMMARY:
==12822==     in use at exit: 0 bytes in 0 blocks
==12822==   total heap usage: 3 allocs, 3 frees, 72,736 bytes allocated
==12822== 
==12822== All heap blocks were freed -- no leaks are possible
==12822== 
==12822== For lists of detected and suppressed errors, rerun with: -s
==12822== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

检测结果第6行和第12行指出,出现无效的写和无效的读;在demo.cpp的第6行存在数组越界访问,无效的写操作;在demo.cpp的第10行出现数组访问越界,无效的读操作;

只能检测动态数组访问越界,静态数组无法检测;

例4 多次内存释放
#include <iostream>
using namespace std;
int main()
{
    int *p2 = new int[4]{1,2,3,4};
    delete []p2;
    delete []p2;
    return 0;
}
==13064== Memcheck, a memory error detector
==13064== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==13064== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==13064== Command: ./demo
==13064== 
==13064== Invalid free() / delete / delete[] / realloc()
==13064==    at 0x4C32BC2: operator delete[](void*) (vg_replace_malloc.c:1115)
==13064==    by 0x4007AB: main (demo.cpp:7)
==13064==  Address 0x5b1fc80 is 0 bytes inside a block of size 16 free'd
==13064==    at 0x4C32BC2: operator delete[](void*) (vg_replace_malloc.c:1115)
==13064==    by 0x400798: main (demo.cpp:6)
==13064==  Block was alloc'd at
==13064==    at 0x4C30989: operator new[](unsigned long) (vg_replace_malloc.c:652)
==13064==    by 0x400757: main (demo.cpp:5
==13064== 
==13064== 
==13064== HEAP SUMMARY:
==13064==     in use at exit: 0 bytes in 0 blocks
==13064==   total heap usage: 2 allocs, 3 frees, 72,720 bytes allocated
==13064== 
==13064== All heap blocks were freed -- no leaks are possible
==13064== 
==13064== For lists of detected and suppressed errors, rerun with: -s
==13064== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

检测结果第6行指出,出现无效的内存释放操作;该内存在demo.cpp文件的第5行申请,demo.cpp的第6行释放,demo.cpp在第7行进行二次释放,错误操作;在结果的第19行也指出,2个内存块申请,3分内存块释放操作,存在错误的内存释放操作;

例5 申请和释放操作不匹配
#include <iostream>
#include <stdlib.h>
int main()
{
    int *p1 = (int*)malloc(sizeof(int)*4);
    delete p1;
    return 0;
}

==13194== Memcheck, a memory error detector
==13194== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==13194== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==13194== Command: ./demo
==13194== 
==13194== Mismatched free() / delete / delete []
==13194==    at 0x4C31C86: operator delete(void*) (vg_replace_malloc.c:935)
==13194==    by 0x40076A: main (demo.cpp:6)
==13194==  Address 0x5b1fc80 is 0 bytes inside a block of size 16 alloc'd
==13194==    at 0x4C2F15A: malloc (vg_replace_malloc.c:393)
==13194==    by 0x40075A: main (demo.cpp:5)
==13194== 
==13194== 
==13194== HEAP SUMMARY:
==13194==     in use at exit: 0 bytes in 0 blocks
==13194==   total heap usage: 2 allocs, 2 frees, 72,720 bytes allocated
==13194== 
==13194== All heap blocks were freed -- no leaks are possible
==13194== 
==13194== For lists of detected and suppressed errors, rerun with: -s
==13194== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

检测结果第6行指出,存在内存申请和释放的操作不匹配;在demo.cpp文件的第6行使用了malloc申请内存,在demo.cpp文件的第6行使用了delete操作,内存申请和释放的操作不匹配;

具体使用手册参考:Valgrind

官网:Valgrind Home

Sanitizer

简介

​ Address Aanitizer是一个快速检测内存错误的工具,它只将程序运行的速度拖慢了两倍,相比valgrand的10~20倍来说性能已经非常好了;他主要包含一个编译器instrumentation模块和一个替换malloc()/free()函数的运行时动态库;

GCC从4.8开始,AddressSanitizer就成为其一部分,一般建使用gcc4.9以上的版本;

原理

​ ASAN(AddressSanitizer)运行时,将malloc()/free() 进行了替换;malloc()分配缓存前后的空间以及被free()释放的空间都标记位poisoned,替换情况如下:

//替换前
*address = ...;
//替换后
if (IsPoisoned(addrss))
{
    ReportError(address, kAccessSize, kIsWrite);
}
//访问之前检查地址是否可以访问
*address = ...;
使用步骤
  1. 编译时需要添加 -fsanitize=address 编译选项
  2. 添加 -fno-omit-frame-pointer 编译选项,可得到更详细的stack trace
  3. 选择 -O1 或者更高级别的编译优化选项
gcc -fsanitize=address -fno-omit-frame-pointer -O1 -g demo.cpp -o demo
错误类型
  • 堆(heap)use after free 释放后使用

    int main ()
    {
        int* p = new int(10);
        delete p;
        return *p;
    }
    
  • heap buffer overflow 堆缓存访问溢出

    int main()
    {
        int* arr[10] = new int[10];
        int a = arr[10];
        return 0;
    }
    
  • stack buffer overflow 栈缓存访问益处

    int main()
    {
        int arr[10] = {10};
        int a = arr[10];
        return 0;
    }
    
  • global buffer overflow 全局缓存访问益处

    int arr[10] = {10};
    int main()
    {
        int a = arr[10];
        return 0;
    }
    
  • memory leaks 内存泄漏

    int main()
    {
        int* a = new int(10);
        return 0;
    }
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++内存分析工具 的相关文章

  • 如何在多线程C++ 17程序中交换两个指针?

    我有两个指针 pA 和 pB 它们指向两个大的哈希映射对象 当pB指向的哈希图完全更新后 我想交换pB和pA 在C 17中 如何快速且线程安全地交换它们 原子 我是 c 17 的新手 2个指针的原子无等待交换可以通过以下方式实现 inclu
  • 如何捕获未发送到 stdout 的命令行文本?

    我在项目中使用 LAME 命令行 mp3 编码器 我希望能够看到某人正在使用什么版本 如果我只执行 LAME exe 而不带参数 我会得到 例如 C LAME gt LAME exe LAME 32 bits version 3 98 2
  • 代码 GetAsyncKeyState(VK_SHIFT) & 0x8000 中的这些数字是什么?它们是必不可少的吗?

    我试图在按下按键的简单动作中找到这些数字及其含义的任何逻辑解释 GetAsyncKeyState VK SHIFT 0x8000 可以使用哪些其他值来代替0x8000它们与按键有什么关系 GetAsyncKeyState 根据文档返回 如果
  • 以编程方式读取 SQL Server 查询计划建议的 SQL 特定执行的索引?

    如果我在 SSMS 中运行此命令 set showplan xml on GO exec some procedure arg1 arg2 arg3 GO set showplan xml off GO 我获得查询执行中涉及的完整调用堆栈的
  • GetType() 在 Type 实例上返回什么?

    我在一些调试过程中遇到了这段代码 private bool HasBaseType Type type out Type baseType Type originalType type GetType baseType GetBaseTyp
  • 查找进程的完整路径

    我已经编写了 C 控制台应用程序 当我启动应用程序时 不使用cmd 我可以看到它列在任务管理器的进程列表中 现在我需要编写另一个应用程序 在其中我需要查找以前的应用程序是否正在运行 我知道应用程序名称和路径 所以我已将管理对象搜索器查询写入
  • 从客户端访问 DomainService 中的自定义对象

    我正在使用域服务从 Silverlight 客户端的数据库中获取数据 在DomainService1 cs中 我添加了以下内容 EnableClientAccess public class Product public int produ
  • unordered_map 中字符串的 C++ 哈希函数

    看起来 C 标准库中没有字符串的哈希函数 这是真的 在任何 c 编译器上使用字符串作为 unordered map 中的键的工作示例是什么 C STL提供模板专业化 http en cppreference com w cpp string
  • 对 std::vector 进行排序但忽略某个数字

    我有一个std vector
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • File.AppendText 尝试写入错误的位置

    我有一个 C 控制台应用程序 它作为 Windows 任务计划程序中的计划任务运行 此控制台应用程序写入日志文件 该日志文件在调试模式下运行时会创建并写入应用程序文件夹本身内的文件 但是 当它在任务计划程序中运行时 它会抛出一个错误 指出访
  • 类型约束

    我有以下类层次结构 class Header IEnumerable
  • 使用valgrind进行GDB远程调试

    如果我使用远程调试gdb我连接到gdbserver using target remote host 2345 如果我使用 valgrind 和 gdb 调试内存错误 以中断无效内存访问 我会使用 target remote vgdb 启动
  • 在视口中查找 WPF 控件

    Updated 这可能是一个简单或复杂的问题 但在 wpf 中 我有一个列表框 我用一个填充数据模板从列表中 有没有办法找出特定的数据模板项位于视口中 即我已滚动到其位置并且可以查看 目前我连接到了 listbox ScrollChange
  • 高效列出目录中的所有子目录

    请参阅迄今为止所采取的建议的编辑 我正在尝试使用 WinAPI 和 C 列出给定目录中的所有目录 文件夹 现在我的算法又慢又低效 使用 FindFirstFileEx 打开我正在搜索的文件夹 然后我查看目录中的每个文件 使用 FindNex
  • Unity:通过拦截将两个接口注册为一个单例

    我有一个实现两个接口的类 我想对该类的方法应用拦截 我正在遵循中的建议Unity 将两个接口注册为一个单例 https stackoverflow com questions 1394650 unity register two inter
  • WebBrowser.Print() 等待完成。 。网

    我在 VB NET 中使用 WebBrowser 控件并调用 Print 方法 我正在使用 PDF 打印机进行打印 当调用 Print 时 它不会立即启动 它会等到完成整个子或块的运行代码 我需要确保我正在打印的文件也完整并继续处理该文件
  • String.Empty 与 "" [重复]

    这个问题在这里已经有答案了 可能的重复 String Empty 和 有什么区别 https stackoverflow com questions 151472 what is the difference between string
  • 如何在richtextbox中使用多颜色[重复]

    这个问题在这里已经有答案了 我使用 C windows 窗体 并且有 richtextbox 我想将一些文本设置为红色 一些设置为绿色 一些设置为黑色 怎么办呢 附图片 System Windows Forms RichTextBox有一个
  • 如何使用 C++11 using 语法键入定义函数指针?

    我想写这个 typedef void FunctionPtr using using 我该怎么做呢 它具有类似的语法 只不过您从指针中删除了标识符 using FunctionPtr void 这是一个Example http ideone

随机推荐

  • Java JDK 安装及环境配置教程

    一 安装 1 安装包 jdk1 8安装包下载路径 2 创建一个英文的文件夹 注意 整个路径不要有中文 建议文件夹直接命名为JDK 3 在该文件夹下创建两个空文件夹 分别为 jdk1 8 和 jre 其中jdk1 8 是我的JDK版本 这个可
  • 还是搜索、索引的问题

    搜索要弄清2个基本问题 1 要搜索出什么类型的entity 2 entity的哪个方面 维度和关键词发生关联的 一般来说可以有多个角度link到entity 一个entity支持多个索引 可以从不同的column检索 对于 web sear
  • elasticsearch ubuntu 安装

    之前 一直听说 Elasticsearch功能强大 我今天安装了下 到pypi里看了下 并安装到虚拟环境中 本以为它就是一个包呢 所以试着用 结果出问题了 后来一看 原来它也是分服务端可客户端的 pypi里的这个是客户端 搭建很简单 所以我
  • Qt Qstring字符串的查找、替换、切割操作

    文章目录 查找 替换replace 字符串切割 查找 直接上代码 include
  • 手把手教你使用simulink配合STM32CUBEMX (生成keil项目实战)

    本文的作者在自学过程中发现该类资料的缺少 以及前人叙述不够完善的情况下 进行了本文的创作 文章将一步一步的讲解如何使用simulink将F4的灯点亮 更多的功能我们一起探索 别的型号的 cpu 大家可以类比进行 1 首先是将MATLAB安装
  • 模拟HashSet

    package chain 单链表 节点 Map中的Entry
  • 国际版阿里云/腾讯云CDN装备运用教程:加快网站拜访速度

    阿里云CDN装备运用教程 加快网站拜访速度 本文旨在为读者供给一个关于阿里云CDN的简要教程 咱们将介绍阿里云CDN的基本概念 资源加快过程 同步资源设置以及与阿里云OSS目标存储的结合 期望经过这篇教程 读者能够更好地了解和利用阿里云CD
  • 感知机

    统计学习方法 此书中 将感知机模型讲解十分清楚 并且推导了损失函数设计原理 随机梯度下降方法求解参数 详细解释了对偶问题求解方法及模型的收敛性 笔者再次学习该模型后 将自己的理解融入本文中 从感知机模型 损失函数设定 计算策略 算法流程这4
  • vue create is a Vue CLI 3 only command and you are using Vue CLI 2.9.6. You may want to run the

    这是应为vue的版本存在更新 需要先卸载vue cli2 然后重新安装vue cli 3 1 卸载vue cli2 npm uninstall vue cli g 或 yarn global remove vue cli 2 安装vue c
  • TCP报文段首部格式介绍

    1 TCP报文段首部格式tu 2 头部各个字段介绍 1 源端口和目的端口 源端口和目的端口字段各占 2 字节 端口是运输层与应用层的服务接口 运输层的复用和分用功能都要通过端口才能实现 2 序号字段 序号字段占 4 字节 要明确的是 TCP
  • WebService报错javax.xml.ws.soap.SOAPFaultException: javax.xml.ws.WebFault.messageName()

    原文地址 http blog csdn net woshixuye article details 14312579 一 发现问题 JAX WS规范是一组XML web services的JAVA API JAXWS RI是其的一个包 用j
  • 面试-大数据-场景题-sql

    1 求5min内浏览次数达到100的用户 LAG和LEAD函数 转载自 有如下场景 某公司网站每日访问量达到10亿级别的访问量 每次访问记录一条数据 数据包含如下字段 用户ID 访问时间 毫秒级 访问页面 要求使用hive求出所有在5分钟内
  • 卷积神经网络的三个特性

    转载 elecfans com emb fpga 20171116580425 2 html 局部感知 形象地说 就是模仿你的眼睛 想想看 你在看东西的时候 目光是聚焦在一个相对很小的局部的吧 严格一些说 普通的多层感知器中 隐层节点会全连
  • 关于C#模拟LED

    如下图 不管是用什么控件 或者是richTextBox 或者是TextBox 等等 我想应该都可以做得出下面这种效果来 但是 本人研究了快半个月了 可以说也没有找到什么很好的头绪 所以 干脆就粘贴在我的博客中了 希望看到的朋友给我个意见或者
  • c语言在输入字符串时输入空格的方式

    1 最容易的 将一个字符串分为一个一个字符输入 char s 100 int i 0 while scanf c s i s i n i s i 0 遇到换行停止输入 并且将换行替换为 0 printf s n s 但是如果在这段程序前还有
  • 每日一题:最大和上升子序列

    最大和上升子序列 题目 Daimayuan Online Judge 动态规划 和最长上升子序列类似 状态划分 以第i个数结尾的上升子序列的倒数第二个数可能是第一个数 第二个数 第i 1个数 从第一个数开始枚举 以它为结尾 首先f i a
  • bboss 流批一体化框架 与 数据采集 ETL

    数据采集 ETL 与 流批一体化框架 特性 高效 稳定 快速 安全 bboss 是一个基于开源协议 Apache License 发布的开源项目 主要由以下三部分构成 Elasticsearch Highlevel Java Restcli
  • feign调用使用Apache Http遇到问题汇总

    feign调用使用Apache Http目前已知会造成三个问题 1 RequestMapping必须显式指定调用方式 method RequestMethod POST 否则默认会使用get请求 这会造成之前一些没有显式指定调用方式的方法报
  • linux下quartus出现ModelSim executable not found和Unable to checkout a license. Make sure...... 错误

    一定要把Tools gt Options gt EDA Tool Options设置到bin下YOUR PATH altera 13 1 modelsim ase bin 注意是modelsim ase不是modelsim ae 而且有bi
  • C++内存分析工具

    C 内存分析工具 背景 内存泄漏在c 中是一个常见的问题 有一个好用的内存分析工具就是很有必要的 下面来介绍两个简单好用的内存分析工具 Valgrind和Sanitizer Valgrind valgrind是一种非侵入式的内存检测工具 在