有人在iPhone应用程序中成功使用CFAllocator SetDefault吗?

时间:2013-06-16 16:35:31

标签: iphone ios memory-management uiwebview core-foundation

我希望用我自己的实现替换iPhone应用中的默认CFAllocator。我想控制UIWebView分配的内存,因为它在加载网站后似乎保留了这么多内存,并且在释放UIWebView时内存仍然存在。

在我致电CFAllocatorSetDefault后,我在下次分配时遇到EXC_BREAKPOINT例外。

异常似乎发生在对CFRetain的调用中(在模拟器中完成但在设备上发生同样的事情):

CoreFoundation`CFRetain:
0x1c089b0:  pushl  %ebp
0x1c089b1:  movl   %esp, %ebp
0x1c089b3:  pushl  %edi
0x1c089b4:  pushl  %esi
0x1c089b5:  subl   $16, %esp
0x1c089b8:  calll  0x1c089bd                 ; CFRetain + 13
0x1c089bd:  popl   %edi
0x1c089be:  movl   8(%ebp), %esi
0x1c089c1:  testl  %esi, %esi
0x1c089c3:  jne    0x1c089db                 ; CFRetain + 43
0x1c089c5:  int3   
0x1c089c6:  calll  0x1d66a00 ; symbol stub for: getpid <- EXC_BREAKPOINT (code=EXC_I386_BPT subcode=0x0)
0x1c089cb:  movl   %eax, (%esp)
0x1c089ce:  movl   $9, 4(%esp)
0x1c089d6:  calll  0x1d66a4e                 ; symbol stub for: kill
0x1c089db:  movl   (%esi), %eax
0x1c089dd:  testl  %eax, %eax
0x1c089df:  je     0x1c08a17                 ; CFRetain + 103
0x1c089e1:  cmpl   1838519(%edi), %eax
0x1c089e7:  je     0x1c08a17                 ; CFRetain + 103
0x1c089e9:  movl   4(%esi), %ecx
0x1c089ec:  shrl   $8, %ecx
0x1c089ef:  andl   $1023, %ecx
0x1c089f5:  cmpl   1834423(%edi,%ecx,4), %eax
0x1c089fc:  je     0x1c08a17                 ; CFRetain + 103
0x1c089fe:  movl   1766575(%edi), %eax
0x1c08a04:  movl   %eax, 4(%esp)
0x1c08a08:  movl   %esi, (%esp)
0x1c08a0b:  calll  0x1d665c8                 ; symbol stub for: objc_msgSend

1 个答案:

答案 0 :(得分:5)

更新

Core Foundation有一个使CFAllocatorSetDefault无效的错误。

具体来说,如果您在CFRuntime.c中研究_CFRuntimeCreateInstance的实施,您会看到:

  • 如果它没有使用系统默认分配器,它会尝试保留分配器。
  • 如果已将NULL作为allocator参数传递,它将尝试保留NULL而不是当前的默认分配器。
  • CFRetain的调用因此会崩溃。

应该做的是当NULL作为allocator参数时,保留当前的默认分配器。

由于Apple自己的库中的许多函数显然将NULL(或kCFAllocatorDefault(也是空指针)传递给创建Core Foundation对象的函数,因此如果快速崩溃,则必然会很快崩溃。你根本就改变了默认的分配器。

我的测试用例:我创建了一个新的单视图iPhone应用程序。我在main添加了一行:

int main(int argc, char *argv[])
{
    CFAllocatorSetDefault(kCFAllocatorMalloc);
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

应用程序在模拟器和我的测试设备上启动时在CFRetain中使用EXC_BREAKPOINT崩溃,并使用空指针作为函数参数。

ORIGINAL

您正在将空指针传递给CFRetain。如果这与您的自定义分配器有关,则需要发布更多详细信息,例如发生异常时的完整调用堆栈。

在您的反汇编列表中,0x1c089b00x1c089bd的说明是功能序言。

0x1c089bemovl 8(%ebp), %esi指令将堆栈中的第一个函数参数加载到%esi

0x1c089c1testl %esi, %esi指令根据%esi的值设置处理器标志。特别是,如果%esi包含零,它会将Z(零)标志设置为1,如果%esi包含其他任何内容,则将Z标志设置为0。

0x1c089c3,如果jne 0x1c089db条件为真,则ne指令跳转。当Z标志为0时ne条件为真,而当Z标志为1时为假。因此当%esi(第一个参数)非零时该指令跳转,并且当%esi0x1c089c5条件跳转1}}为零。

int3SIGTRAP指令会引发EXC_BREAKPOINT信号,异常代码为int3。设置断点时,调试器通常会将CFRetain指令填充到程序中。在这种情况下,它在编译时在程序中进行了硬编码。

因此,您将获得此异常,因为您将空指针传递给CFRetain

如果您愿意,还可以查看CFTypeRef CFRetain(CFTypeRef cf) { if (NULL == cf) { CRSetCrashLogMessage("*** CFRetain() called with NULL ***"); HALT; } if (cf) __CFGenericAssertIsCF(cf); return _CFRetain(cf, false); } 的源代码。它位于CFRuntime.c

CFRetain

所以NULL做的第一件事就是测试它的参数是否为CGSetCrashLogMessageHALTCoreFoundation_Prefix.h中定义的宏,不执行任何操作。 #define HALT do {asm __volatile__("int3"); kill(getpid(), 9); } while (0) CFInternal.h中定义的宏:

HALT

如您所见,int3有一条硬编码的kill(getpid(), 9)指令。然后它调用{{1}}。这与您的反汇编列表相符。