10

假设最新的 XCode 和 GCC,覆盖内存分配函数的正确方法是什么(我猜也是 operator new/delete)。调试内存分配器对于游戏来说太慢了,我只需要一些基本的统计数据,我可以自己做,影响最小。

我知道由于钩子在 Linux 中它很容易,十年前我在编写 HeapManager 时,这在 codewarrior 中是微不足道的。

可悲的是 smartheap 不再有 mac 版本。

4

7 回答 7

10

我会为此任务使用库预加载,因为它不需要修改正在运行的程序。如果您熟悉执行此操作的常用 Unix 方法,则几乎只需将 LD_PRELOAD 替换为 DYLD_INSERT_LIBRARIES。

第一步是使用这样的代码创建一个库,然后使用常规共享库链接选项 ( gcc -dynamiclib) 构建它:

void *malloc(size_t size)
{
    void * (*real_malloc)(size_t);
    real_malloc = dlsym(RTLD_NEXT, "malloc");

    fprintf(stderr, "allocating %lu bytes\n", (unsigned long)size);
    /* Do your stuff here */

    return real_malloc(size);
}

请注意,如果您还转移calloc()及其实现调用malloc(),您可能需要额外的代码来检查您是如何被调用的。C++ 程序应该非常安全,因为无论如何new操作符都会调用malloc(),但请注意,没有标准强制执行此操作。不过,我从未遇到过不使用的实现malloc()

最后,为您的程序设置运行环境并启动它(可能需要根据 shell 处理环境变量的方式进行调整):

export DYLD_INSERT_LIBRARIES=./yourlibrary.dylib
export DYLD_FORCE_FLAT_NAMESPACE=1
yourprogram --yourargs

有关动态链接器环境变量的更多信息,请参见dyld 手册页

这个方法很通用。但是有一些限制:

  • 您将无法转移直接系统调用
  • 如果应用程序本身通过使用dlsym()to loadmalloc的地址来欺骗您,则呼叫不会被转移。但是,除非您还通过转移来欺骗它dlsym
于 2009-05-31T11:17:43.967 回答
3

http://lists.apple.com/archives/darwin-dev/2005/Apr/msg00050.htmlmalloc_default_zone中提到的技术似乎仍然有效,请参见http://code.google.com/p/fileview/source/ browse/trunk/fileview/fv_zone.cpp?spec=svn354&r=354的示例用法似乎与您的意图相似。

于 2009-05-30T15:50:02.423 回答
1

经过大量搜索(包括这里)和 10.7 的问题后,我决定写一篇关于这个主题的博客文章:How to set malloc hooks in OSX Lion

您会在文章末尾找到一些很好的链接,其中包含有关此主题的更多信息。

基本解决方案:

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
}
于 2011-07-29T10:14:04.023 回答
1

这是一个古老的问题,但我在尝试自己做这件事时遇到了它。对于我正在从事的个人项目,我对这个主题感到好奇,主要是为了确保我认为自动解除分配的内容被正确解除分配。我最终编写了一个 C++ 实现,以允许我跟踪分配的堆的数量并在我选择时将其报告出来。

https://gist.github.com/monitorjbl/3dc6d62cf5514892d5ab22a59ff34861

顾名思义,这是特定于 OSX 的。但是,我能够在 Linux 环境中使用malloc_usable_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

希望这对将来的其他人有所帮助!

于 2016-06-30T18:51:09.833 回答
0

如果您需要的基本统计数据可以收集在一个简单的包装器中,那么一个快速(而且有点脏)的技巧就是使用一些#define宏替换。

void* _mymalloc(size_t size)
{
    void* ptr = malloc(size);

    /* do your stat work? */

    return ptr;
}

#define malloc(sz_) _mymalloc(sz_)

注意:如果宏是在 _mymalloc 定义之前定义的,它将最终替换该函数内的 malloc 调用,从而使您陷入无限递归……因此请确保不是这种情况。您可能希望#undef在该函数定义之前显式地定义它,然后根据最终包含它的位置简单地(重新)定义它,以希望避免这种情况。

于 2009-05-30T15:52:41.800 回答
0

我认为如果您在项目中包含的自己的 .c 文件中定义 malloc() 和 free() ,链接器将解析该版本。

那么,你打算如何实现malloc呢?

于 2009-05-30T16:31:36.867 回答
0

https://github.com/emeryberger/Heap-Layers/blob/master/wrappers/macwrapper.cpp(以及一些其他文件,您可以按照包含跟踪自己)。

这是对亚历克斯的回答的补充,但我认为这个例子更重要的是替换系统提供的分配器。

于 2014-07-22T05:51:56.623 回答