Juce源码分析(五)对象泄露探测器

        内存泄漏形象的比喻是“操作系统可提供给所有进程的存储空间正在被某个进程榨干”,最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以“内存泄漏”是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄露了。

       引起内存泄露的原因主要是,由于使用new关键字在堆中创建对象,或者使用malloc之类的在堆中开辟内存,没有释放连续积累造成的。例如,我们经常有这样的操作,我们右击弹出一个菜单,然后点击一个菜单项,菜单就会消失,当菜单弹出时要开辟内存,那么在菜单消失时,理所当然应该释放内存,否则,在菜单的不断使用过程中,程序的内存占有量会持续上升,直至程序崩溃。记得Duilib的MenuDemo出现过类似的问题,但是后来被修复了。虽然内存泄露很容易被发现,打开任务管理器肉眼观察就行了,但是寻找泄露根源是非常不容易的,代码越是复杂越难找。

     Juce为我们提供了LeakedObjectDetector,我自己给它翻译成“对象泄露探测器”,这里得注意措辞,是“对象”泄露探测器,也就是说只能能探测new出来的对象,用malloc等搞出来的内存就不好使了。LeakedObjectDetector的作用是记录对象创建和释放的次数差,当程序退出时,两者平衡了,说明正常,否则就是内存泄露或者重复释放,由于代码比较简单,所以只能定位到是哪个类发生了泄露,想得到再具体的信息就无能为力了。

     下面是我经过简单修改后的代码(只是修改了出现异常后的提示信息)

template <class OwnerClass>
class LeakedObjectDetector                    //Object泄露探测器
{
public:

	LeakedObjectDetector()                                  { ++(getCounter().numObjects); }       //创建对象时,计数器自加
	LeakedObjectDetector (const LeakedObjectDetector&)      { ++(getCounter().numObjects); }

	~LeakedObjectDetector()        //对象析构时,计数器自减,当计数器记录的值为负值时,显然释放的次数大于创建的次数,说明有重复释放现象
	{
		if (--(getCounter().numObjects) < 0)
		{
			LPTSTR LeakedMessage = new TCHAR[64];

			_stprintf(LeakedMessage,_T("对象类型:%s\n对象个数:%d"),getLeakedObjectClassName(),getCounter().numObjects.getValue());
			MessageBox(0,LeakedMessage,L"重复释放",0);
		}
	}
private:                                
	class LeakCounter             //对象计数器
	{
	public:
		LeakCounter()  {}

		~LeakCounter()            //当程序退出时,静态计数器会析构,这时统计当前对象的个数,为泄露对象的个数
		{
			if (numObjects.get() > 0)
			{
				LPTSTR LeakedMessage = new TCHAR[64];
				_stprintf(LeakedMessage,_T("对象类型:%s\n对象个数:%d"),getLeakedObjectClassName(),numObjects.getValue());
				MessageBox(0,LeakedMessage,L"内存泄露",0);

				delete LeakedMessage;
			}
		}
		Atomic<int> numObjects;        //原子int类型
	};
	static const LPTSTR getLeakedObjectClassName()
	{
		return OwnerClass::getLeakedObjectClassName();
	}

	static LeakCounter& getCounter()       //静态计数器
	{
		static LeakCounter counter;
		return counter;
	}
};



#define LEAK_DETECTOR(OwnerClass) \
	friend class LeakedObjectDetector<OwnerClass>; \
	static const LPTSTR getLeakedObjectClassName()  { return _T(#OwnerClass); } \
	LeakedObjectDetector<OwnerClass> leakDetector##OwnerClass;

于是,我们就可以这样使用了

class A

{

public:

     A()

     {

     }

    ~A()

    {

    }

private:

   LEAK_DETECTOR(A)

}

当使用A创建的对象,或者A的子类创建的对象发生内存泄露时,就会出现相应的提示信息




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Skilla

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值