Xcode 如何在OS X下重写malloc()、calloc()、free()等?
假设使用最新的XCode和GCC,那么覆盖内存分配函数的正确方法是什么(我猜操作符new/delete也是如此)。调试内存分配器对于一个游戏来说太慢了,我只需要一些基本的统计数据,我可以用最小的影响自己完成 我知道在Linux中使用钩子很容易,而在十年前我编写HeapManager时,在codewarrior中这是微不足道的Xcode 如何在OS X下重写malloc()、calloc()、free()等?,xcode,macos,malloc,overriding,Xcode,Macos,Malloc,Overriding,假设使用最新的XCode和GCC,那么覆盖内存分配函数的正确方法是什么(我猜操作符new/delete也是如此)。调试内存分配器对于一个游戏来说太慢了,我只需要一些基本的统计数据,我可以用最小的影响自己完成 我知道在Linux中使用钩子很容易,而在十年前我编写HeapManager时,在codewarrior中这是微不足道的 遗憾的是,smartheap不再有mac版本。中提到的malloc\u default\u zone技术似乎仍然有效,例如,请参阅一个与您的意图类似的示例用法。如果您需要的
遗憾的是,smartheap不再有mac版本。中提到的
malloc\u default\u zone
技术似乎仍然有效,例如,请参阅一个与您的意图类似的示例用法。如果您需要的基本统计信息可以在一个简单的包装器中收集,请使用一个快速(而且有点脏)的技巧就是使用一些#define
宏替换
void* _mymalloc(size_t size)
{
void* ptr = malloc(size);
/* do your stat work? */
return ptr;
}
及
注意:如果宏是在_mymalloc定义之前定义的,那么它最终将替换该函数中的malloc调用,从而给您留下无限递归。。。因此,请确保情况并非如此。您可能希望在函数定义之前显式定义它,然后根据最终包含它的位置简单地(重新)定义它,以避免出现这种情况。我认为如果您在项目中包含的自己的.c文件中定义malloc()和free(),链接器将解析该版本
现在,您打算如何实现malloc?我将使用库预加载来完成此任务,因为它不需要修改正在运行的程序。如果您熟悉常用的Unix方法,那么几乎只需使用DYLD_INSERT_库替换LD_PRELOAD即可 第一步是使用这样的代码创建库,然后使用常规共享库链接选项(
gcc-dynamiclib
)构建它:
请注意,如果您还转移了calloc()
及其实现调用malloc()
,则可能需要额外的代码来检查如何调用您。C++程序应该非常安全,因为<代码>新< /Cuff>操作符调用<代码> MalCube()/<代码>,但请注意,没有标准强制执行。不过,我从未遇到过不使用malloc()
的实现
最后,为您的程序设置运行环境并启动它(可能需要根据shell处理环境变量的方式进行调整):
有关动态链接器环境变量的详细信息,请参阅
这种方法非常通用。但是,也有一些限制:
- 您将无法转接直接系统呼叫
- 如果应用程序本身通过使用
加载dlsym()
的地址来欺骗您,那么调用将不会被转移。但是,除非您通过转移malloc
来欺骗它!dlsym
malloc_zone_t *dz=malloc_default_zone();
if(dz->version>=8)
{
vm_protect(mach_task_self(), (uintptr_t)malloc_zones, protect_size, 0, VM_PROT_READ | VM_PROT_WRITE);//remove the write protection
}
original_free=dz->free;
dz->free=&my_free; //this line is throwing a bad ptr exception without calling vm_protect first
if(dz->version==8)
{
vm_protect(mach_task_self(), (uintptr_t)malloc_zones, protect_size, 0, VM_PROT_READ);//put the write protection back
}
查看Emery Berger的《囤积内存分配器》一书的作者,他提出了一种在OSX上替换分配器的方法(以及一些其他文件,您可以通过以下内容来跟踪自己)
这是对Alex答案的补充,但我认为这个例子更接近于替换系统提供的分配器。这是一个老问题,但我自己在尝试这样做时遇到了它。我对我正在进行的一个个人项目中的这个话题感到好奇,主要是为了确保我认为自动释放的东西被正确地释放。最后,我写了一个C++实现,让我跟踪分配的堆的数量,如果我选择的话,报告它。p> 顾名思义,这是OSX特有的。但是,我可以在Linux环境中使用
malloc\u-available\u-size
示例
#define MALLOC_DEBUG_OUTPUT
#include "malloc_override_osx.hpp"
int main(){
int* ip = (int*)malloc(sizeof(int));
double* dp = (double*)malloc(sizeof(double));
free(ip);
free(dp);
}
建筑
$ clang++ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk \
-pipe -stdlib=libc++ -std=gnu++11 -g -o test test.cpp
$ ./test
0x7fa28a403230 -> malloc(16) -> 16
0x7fa28a403240 -> malloc(16) -> 32
0x7fa28a403230 -> free(16) -> 16
0x7fa28a403240 -> free(16) -> 0
希望这有助于其他人在未来这不能用C++运算符new /Delphi或没有源代码的库来操作,因为我为操作员找到了新的,非常好,现在来想一下MalOC/CalOthTy是一个很好的例子,但是我认为一个更干净的例子,完全替代了OSX的内存分配器。还是。。。原始的电子邮件线程非常棒。:)注册一个新的默认区域是可行的,但如果你只需要一些“基本的统计数据”,这有时会太多,就像问题所指出的那样。进入默认区域更容易,但它不再像Alex所描述的那样起作用。那么,为什么对一个只帮助解决问题的答案投反对票而不发表任何评论呢?
malloc_zone_t *dz=malloc_default_zone();
if(dz->version>=8)
{
vm_protect(mach_task_self(), (uintptr_t)malloc_zones, protect_size, 0, VM_PROT_READ | VM_PROT_WRITE);//remove the write protection
}
original_free=dz->free;
dz->free=&my_free; //this line is throwing a bad ptr exception without calling vm_protect first
if(dz->version==8)
{
vm_protect(mach_task_self(), (uintptr_t)malloc_zones, protect_size, 0, VM_PROT_READ);//put the write protection back
}
#define MALLOC_DEBUG_OUTPUT
#include "malloc_override_osx.hpp"
int main(){
int* ip = (int*)malloc(sizeof(int));
double* dp = (double*)malloc(sizeof(double));
free(ip);
free(dp);
}
$ clang++ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk \
-pipe -stdlib=libc++ -std=gnu++11 -g -o test test.cpp
$ ./test
0x7fa28a403230 -> malloc(16) -> 16
0x7fa28a403240 -> malloc(16) -> 32
0x7fa28a403230 -> free(16) -> 16
0x7fa28a403240 -> free(16) -> 0