2

我希望CFAllocator用我自己的实现替换我的 iPhone 应用程序中的默认设置。我想控制由分配的内存,因为它似乎在加载网站后保留了这么多内存,并且在释放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
4

1 回答 1

5

更新

Core Foundation 有一个错误,使CFAllocatorSetDefault之无用。

具体来说,如果您研究_CFRuntimeCreateInstancein的实现CFRuntime.c,您会看到:

  • 如果它没有使用系统默认分配器,它会尝试保留分配器。
  • 如果它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, with中EXC_BREAKPOINT,使用空指针作为函数参数。

原来的

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

在您的反汇编清单中,0x1c089b0通过的说明0x1c089bd是函数序言。

0x1c089be处,该movl 8(%ebp), %esi指令将第一个函数参数从堆栈加载到%esi.

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

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

0x1c089c5,int3指令产生一个SIGTRAP带有异常代码的信号EXC_BREAKPOINT。当您设置断点时,该int3指令通常由调试器填充到程序中。在这种情况下,它在编译时被硬编码在程序中。

因此,您收到此异常是因为您将空指针传递给CFRetain.

喜欢的也可以看看源代码CFRetain。它在CFRuntime.c

CFTypeRef CFRetain(CFTypeRef cf) {
    if (NULL == cf) { CRSetCrashLogMessage("*** CFRetain() called with NULL ***"); HALT; }
    if (cf) __CFGenericAssertIsCF(cf);
    return _CFRetain(cf, false);
}

所以首先要做的CFRetain是测试它的论点是否是NULL. CGSetCrashLogMessage是一个在其中定义的宏CoreFoundation_Prefix.h,它什么也不做。 HALT是一个宏定义在CFInternal.h

    #define HALT do {asm __volatile__("int3"); kill(getpid(), 9); } while (0)

如您所见,HALT有一个硬编码int3指令。然后它调用kill(getpid(), 9). 这与您的反汇编列表相匹配。

于 2013-06-16T22:20:19.550 回答