内存泄露 工具

内存溢出

out of memory:指程序在申请内存时,没有足够的内存空间供其使用(要求分配的内存超出了系统能给你的,系统不能满足需求)

c++:栈、堆

栈:1M

stack overflow
这个大小可以从编译器的属性中修改,但尽量不修改,不够用了又不得不用再去修改。

堆:4G

  • C语言
	void *malloc(size_t size);

申请一块大小为size的空间,需要用memset()初始化

	void * realloc(void * ptr, size_t new_size);

用于扩大、缩小一个堆空间。ptr为null时,作用和malloc一样
当ptr不为空,设置原来分配的空间n,当new_size<n;缩小ptr所指向的内存空间,该内存块尾部的部分内存被拿掉。当new_size>n时,扩大*ptr所指向的内存空间,所有原来的空间尾部 有足够分配的空间,那么直接分配,没有则需要重新获取一块空间,拷贝原来的数据,释放原来的空间,并返回新的*ptr。

  • C++

new 和delete 是C++ 定义的关键字,通过特定的语法可以组成表达式。
标准库函数实现,不是重载 new 和 delete 表达式,因为 new 和 delete 是不允许重载的。

	//C++的库函数:
 	void *operator new(size_t);     //allocate an object
	void *operator delete(void *);    //free an object
	
	void *operator new[](size_t);     //allocate an array
	void *operator delete[](void *);    //free an array
	//C++ 在分配数组空间时多分配了 4 个字节的大小,专门保存数组的大小,在 delete [] 时取出这个保存的数就知道了需要调用析构函数多少次
	/*
	调用析构函数的次数是从数组对象指针前面的 4 个字节中取出;
	传入 operator delete[] 函数的参数不是数组对象的指针 pAa,而是 pAa 的值减 4。
	*/

实现过程

  • pA=new A(10)
    • 1、operator new 标准库函数,传入的参数为 class A 的大小,分配一个类A的内存
    • 2、调用类的构造函数 对分配的内存进行初始化
    • 3、返回新分配并构造好的对象的指针
  • delete pA;
    • 1、调用 pA 指向对象的析构函数
    • 2、调用标准库函数 operator delete 来释放该对象的内存,传入函数的参数为 pA 的值

原因

  • 长期保持某些资源的引用,垃圾回收器无法回收它,从而使该资源不能够及时释放 ---- 》 内存泄露
  • 当需要保存多个耗用内存过大或当加载单个超大的对象时,该对象的大小超过了当前剩余的可用内存空间
    eg:
    - 全都是强引用(深拷贝)
    • 加载大量资源(图片、数据)
    • 死循环(函数递归调用 死循环 一直在增加栈空间的使用)
    • 出现大量的内存泄露
    • 越界访问(c语言中) :strcpy函数需要有’\0’

解决

  • 检查错误日志,查看 “ OutOfMemory ”错误前是否有其它异常或错误
  • 查看代码:递归调用、大量的新对象生成、获取数据库数据的量
  • 排查内存泄露问题

内存泄露

当使用 new/malloc 在堆上动态分配内存时,忘记使用 delete/free对内存进行回收,就出现了内存泄露。当大量的内存泄露出现时,就会影响服务器的性能和处理能力。

C++11:智能指针

解决内存泄露问题,使用智能指针,它会自动回收空间

  • unique-ptr:独占型指针
  • shard-ptr:共享型指针
  • weak-ptr:解决shard-ptr中的死锁问题

linux

解决内存泄露

  • top :查看当前系统运行的程序及其内存情况

通过虚拟内存的变化,如果运行时刻,内存一直在增加,该程序就出现了内存泄露

  • mtrace : 用于查看内存泄露的位置
	//在active.cpp文件
	#include<mcheck.h>	
		···
	//在程序开始处
	mtrace();
	//结束位置
	muntrace();
	//在终端
	//第一种方式
	//绑定,写到这个日志文件
	expert MALLOC_TRACE = ./active.log
	//运行
	./active
	//打开日志文件,找到内存泄露的地址[0x400626],使用addline显示位置
	add2line -f -e active 0x400626
	
	//第二种方式
	//使用mtrace工具,查看active这个cpp文件,把日志写进active.log
	mtrace active  active.log
	//显示文件,可以看到内存泄露的位置 
	cat  active.log
  • mtrace的实现原理
    • hook 钩子

dlsym(RTLD_NEXT, “malloc”);
实现的原理是,mtrace里面有一个dlsym函数,捕抓malloc

防止内存泄露

内存池

1、内存如何分配 mp_malloc()
2、已分配的数据如何组织

  • 内存池核心问题:内存块如何组织

  • 伙伴算法
    先把需要的内存块分配,把剩下内存按照2^n 去分配,如过是相邻的2^k 就合并起来【缺点:回收条件太严谨】

  • slab
    选一个合适的n,把所有内存都分配为2n块,不管申请的大小,直接就给2n。【缺点:只需要1个字节,却分配了2^n个,多余太多】

  • 大小块
    分为大块和小块,eg(32bytes) 分配的时候,通过需要内存的大小分配,每一个块里面,可能是提供了多次分配,只有当所有分配的内存使用完,完全释放后,这个块就会被回收。
    3、内存如何释放 mp_free()

struct mp_pool_small
{
	//当前使用的最后last
	//这个块的最尾部end
	//指向下一个块 next
	unsigned char* last;
	unsigned char* end;
	mp_pool_small* next;
	//加上一个失败,超过多少次分配失败 就不用继续分配它
	int fails;
};
struct mp_pool_large
{
	//中间不再细分
	//指向下一个块 next
	mp_pool_large* next;
	void* alloc;
};
struct mp_pool_s
{
	//指向小块,大块的地址
	mp_pool_small* small;
	mp_pool_large* large;
	//指向当前的小块
	mp_pool_small* current;
};

在这里插入图片描述


gc 垃圾回收

window

工具

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值