内存问题检测工具

内存问题检测工具

C/C++ 语言,程序员可以管理内存,十分便利,但同时灵活的内存访问也带来了很多很多的问题。尤其是那些偶现的,运行成本较高的场景,往往让我们的开发工作效率大大减慢。

一种办法是静态检查,但问题是很多测试场景跑不到,并且误报较多。另外一种就是动态检查工具,本文就是介绍几种 Linux 下运行时的内存检查工具。

一、内存问题

  • memory overrun:写内存越界
  • double free:同一块内存释放两次
查看更多

内存暴增问题剖析与解决

一、问题背景

我们的智能驾驶系统,遇到了 Glibc 的内存暴增问题。系统中实现了一个简单的内存管理模块,在高压力环境下长时间运行(加载感知模型),当内存管理模块的内存释放给 C 运行时库之后,C 运行时库并没有立即把内存归还给操作系统。比如占用的内存为 10GB,释放内存后,通过 TOP 命令查看,有时是 10GB、有时是 5GB,有时是 2GB,内存释放行为非常不确定。

我们系统中的内存管理方式比较简单,使用全局的定长内存池,内存管理模块每次分配/释放 2MB 内存,然后分成 64KB 为单位的一个个小内存块用 hash 加链表的方式进行管理。如果申请的内存小于等于 64KB 时,直接从内存池的空闲链表中获取一个内存块,内存释放时归还空闲链表;如果申请的内存大于 64KB,直接通过C运行时库的 malloc 和 free 获取。某些数据结构涉及到很多小对象的管理,这些数据结构从全局内存池获取内存后再根据数据结构的特点进行组织。为了提高内存申请/释放的效率,减少锁冲突,为每一个线程单独保留 8MB 的内存块,每个线程优先从线程专属的 8MB 内存块获取内存,专属内存不足时才从全局的内存池获取。

系统在高压力、高并发环境下长时间运行会发生内存暴增的现象,最终进程被 OOM 掉。

二、分析解决过程

为了便于跟踪分析问题,在全局的内存池中加入对每个子模块的内存统计功能:每个子模块申请内存时都将子模块编号传给全局的内存池,全局的内存池进行统计。复现问题后发现全局的内存池的统计结果符合预期。

然后我们动用 ASAN 、review 代码 确认没有发现内存泄漏。

查看更多

垃圾回收

一、概念和定义

GC 算法中最重要的两个角色就是 Mutator 和 Collector。

  • Mutator:本意是改变者。这个词所表达的是通过程序来改变对象之间的引用关系。因为我们所写的所有 Java 程序,都有可能改变对象的存活和死亡状态,以及他们之间的引用关系,那么这些 Java 程序就是 Mutator。因为 Java 程序运行所在的这些线程,我们也称为业务线程,所以在某些情况下,Mutator 和业务线程这两个术语是可以混用的。
  • Collector:用于回收空间中的垃圾,所以叫做收集者。根据不同的 GC 算法,Collector 不仅仅是收集,例如在 Mark-Sweep 中,他还负责标记存活对象、识别垃圾对象。执行 Collector 的线程,一般称为 Collector 线程或者 GC 线程。在某些 GC 算法中,业务线程也有可能帮助做垃圾回收的工作。所以,Mutator 和 Collector 只是一种相对的说法,而不是精确的概念。

查看更多

多核CPU同步高速缓存

在多核体系结构中,如果有一个 CPU 修改了内存中的某个值,那么必须有一种机制保证其他 CPU 能够观察到这个修改。于是人们设计了一些协议来规定一个 CPU 对缓存数据的修改,如何同步到另一个 CPU。

本文会介绍简单的 VI 协议和比较完善的 MESI 协议。

一、缓存写策略

第一种场景:当 CPU 修改了缓存中的数据,这些修改什么时候能传播到内存?有两种策略:写回(Write Back)和写直达(Write Through)。

  • 写回策略,CPU 对缓存的修改不会立刻传播到内存,只有当缓存块被替换时,这些被修改的缓存块,才会写回并覆盖内存中过时的数据。
查看更多

缓存的原理

我们把用于存储数据的电路叫做存储器,按照到 CPU 距离的远近,存储器主要分为寄存器、缓存和内存、磁盘。

  • CPU 中的寄存器使用触发器存储一个比特,读写速度最快,但所占电路面积最大。
  • 存储器大体上可以分为只读存储器 ROM 和随机存储器 RAM 两大类。ROM 断电后信息不会丢失,RAM 断电后存储的信息后丢失。
  • 早期的只读存储器往往只能写一次,不能更改。随着技术的进步,逐渐出现了紫光线可擦除 ROM 和电可擦除 ROM。从而使得 ROM 可以多次写入。现代的闪存就是 EEPROM,他是一种电可擦除的可编程 ROM。
查看更多

linux下使用 valgrind 工具进行内存泄漏检测和性能分析

valgrind 工具集包括如下工具

1
2
3
4
5
1、memcheck:检查程序中的内存问题,如泄漏、越界、非法指针等。
2、callgrind:检测程序代码的运行时间和调用过程,以及分析程序性能。
3、cachegrind:分析CPU的cache命中率、丢失率,用于进行代码优化。
4、helgrind:用于检查多线程程序的竞态条件。
5、massif:堆栈分析器,指示程序中使用了多少堆内存等信息。

这几个工具的使用是通过命令:valgrand –tool=name 程序名来分别调用的,当不指定 tool 参数时默认是 –tool=memcheck

一、memcheck

1
2
3
4
5
6
7
8
最常用的工具,用来检测程序中出现的内存问题,所有对内存的读写都会被检测到,一切对malloc、free、new、delete的调用都会被捕获。所以,它能检测以下问题:
1、对未初始化内存的使用;
2、读/写释放后的内存块;
3、读/写超出malloc分配的内存块;
4、读/写不适当的栈中内存块;
5、内存泄漏,指向一块内存的指针永远丢失;
6、不正确的malloc/free或new/delete匹配;
7、memcpy()相关函数中的dst和src指针重叠。

查看更多

valgrind 相关工具

KCachegrind 工具,可视化工具

https://kcachegrind.github.io/html/Home.html

KCachegrind是个图形化界面,主要用于对callgrind分析来的数据进行可视化。
https://sourceforge.net/projects/kcachegrind/

安装 valgrind 和 KCachegrind。

1
2
3
4
5
首先安装 valgrind:https://www.valgrind.org/
获取源代码:wget http://www.valgrind.org/downloads/valgrind-3.14.0.tar.bz2
解压,进入相关目录
./configure --prefix=/home/user1/valgrind
make && make install

查看更多

原理

一、总体概述

  • ptmalloc2 在机器 4核 CPU 2.8GHz 上对于小对象,执行 malloc/free 两个操作大约需要 300 ns,而对于同一操作,tcmalloc 只需要大约 50ns。

  • tcmalloc 减少了多线程程序的锁竞争。对于小对象,使用 TLS,几乎没有竞争。对于大对象,tcmalloc 尝试使用细粒度且高效的自旋锁。在 ptmalloc2 中,不同的分配区之间的内存不能发生移动、复用,可能导致大量的空间浪费。

    比如,有一个多阶段的任务,第一阶段为某一个数据结构申请 100MB 内存,第一阶段完成后,释放了空间;在第二阶段,在同一地址空间开始申请内存,但是有很大可能使用的是不同的分配区,此阶段不会重用第一阶段留下的任何内存,并且会在新的分配区再添加 100MB 空间。造成内存暴增问题

查看更多