在10M的源码中查找内存泄露。
这个是网上随便看的一个面试题,看到博主写的解法,提到一个钩子函数,我连什么是钩子函数都不知道,人家都能想到用这个方法来解决,
感觉自己太龊了,如果面试中问到这种题,肯定挂了。下面先介绍下钩子函数。
摘至网上:
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。对每种类型的钩子由系统来维护一个钩子链,最近安装的钩子放在链的开始,而最先安装的钩子放在最后,也就是后加入的先获得控制权。要实现Win32的系统钩子,必须调用SDK中的API函数SetWindowsHookEx来安装这个钩子函数,这个函数的原型是HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId);,其中,第一个参数是钩子的类型;第二个参数是钩子函数的地址;第三个参数是包含钩子函数的模块句柄;第四个参数指定监视的线程。如果指定确定的线程,即为线程专用钩子;如果指定为空,即为全局钩子。其中,全局钩子函数必须包含在DLL(动态链接库)中,而线程专用钩子还可以包含在可执行文件中。得到控制权的钩子函数在完成对消息的处理后,如果想要该消息继续传递,那么它必须调用另外一个SDK中的API函数CallNextHookEx来传递它。钩子函数也可以通过直接返回TRUE来丢弃该消息,并阻止该消息的传递。
粗略看一下大概是说钩子函数可以截获一个消息并执行我们想要做的事情,一般用法是将钩子函数作为一个函数参数,下面的例子
#include <iostream>
using namespace std;
//钩子函数1
void fun1()
{
cout<<"hello fun1"<<endl;
}
//钩子函数2
void fun2(int n)
{
cout<<"hello fun2 "<<n<<endl;
}
//作为参数传递
int caller1(void (*ptr)())
{
(*ptr)();
return 0;
}
int caller2(int i,void (*ptr)(int))
{
(*ptr)(i);
return 0;
}
int main()
{
caller1(fun1);
caller2(2,fun2);
return 0;
}
那回到这个题目,有个简单的方法是:
可以包装malloc和free,假设为Malloc和Free。之后我们维护一个集合,如果是调用Malloc,则把地址放入到集合中,如果是调用Free,则从集合中去掉该地址。之后把源代码中的所有malloc和free替换成Malloc和Free,运行程序,那么当程序结束时,集合中剩余的地址就是内存泄露的地址。
如果利用钩子函数,大概变成这样子:
比如malloc可能就变成Malloc(size,hook),size是大小,hook是钩子,具体维护集合的代码在hook里实现。
这么多不懂得知识,这么多需要学习的东西阿。。。