gpt4 book ai didi

ios - dispatch_async 是否复制内部 block

转载 作者:可可西里 更新时间:2023-11-01 04:16:07 24 4
gpt4 key购买 nike

给定以下(手动引用计数):

void (^block)(void) = ^ {
NSLog(@"wuttup");
}

void (^async_block)(void) = ^ {
block();
}

dispatch_async(dispatch_get_main_queue(), async_block);

“ block ”会被复制而不是从堆栈中扔掉并销毁吗?

最佳答案

我相信,答案是肯定的。

外部 block 将被异步调度,这会导致运行时在堆上为该 block 制作一个副本。如下所示,并在 Block Implementation Specification - Clang 3.4 Documentation 中进行了描述,内部 block 的导入变量也被复制到堆中。

在 OP 的示例中,我们有一个“ block 引用的导入常量副本”。

我正在使用规范中的示例:

void (^existingBlock)(void) = ...;
void (^vv)(void) = ^{ existingBlock(); }
vv();

规范指出需要 copy_helperdispose_helper 函数:

The copy_helper function is passed both the existing stack based pointer and the pointer to the new heap version and should call back into the runtime to actually do the copy operation on the imported fields within the Block.

规范中的以下示例代码很难破译(实际上缺少描述将外部 block 复制到堆时发生的情况)。无论如何,规范似乎试图表明内部 block 的导入变量将(递归地)复制到外部 block 的原始存储区域。

当外部 block 将被复制到堆上时,似乎内部 block 的导入变量最终也会存在于堆上。

嗯,直觉上,这一切都是有道理的。

我制作了一个小测试程序来演示这一点:(您必须调试和检查反汇编才能弄清楚表面下发生了什么)。

#import <Foundation/Foundation.h>


void foo(int param)
{
int x0 = param;
int x1 = param + 1;
void (^existingBlock)(void) = ^{
int y0 = x0;
int y1 = x1;
printf("&y0: %p\n", &y0);
printf("&y1: %p\n", &y1);
printf("&x0: %p\n", &x0);
printf("&x1: %p\n", &x1);
};

void (^vv)(void) = ^{
int y2 = x0;
int y3 = x1;
existingBlock();
printf("&y2: %p\n", &y2);
printf("&y3: %p\n", &y3);
printf("&x0: %p\n", &x0);
printf("&x1: %p\n", &x1);
};

printf("Stack: &x: %p\n", &x0);
printf("Stack: &x: %p\n", &x1);

printf("------- on main thread -------\n");
vv();

dispatch_async(dispatch_get_global_queue(0, 0), ^{
printf("------- on thread 2 -------\n");
assert(vv);
sleep(1);
int y4 = x0;
int y5 = x1;
vv();
printf("&y4: %p\n", &y4);
printf("&y5: %p\n", &y5);
printf("&x0: %p\n", &x0);
printf("&x1: %p\n", &x1);
});
}

int main(int argc, const char * argv[])
{
@autoreleasepool {

foo(1);
sleep(2);
}
return 0;
}

输出如下:

Stack: &x: 0x7fff5fbff868
Stack: &x: 0x7fff5fbff864
------- on main thread -------
&y0: 0x7fff5fbff70c
&y1: 0x7fff5fbff708
&x0: 0x1001081e0
&x1: 0x1001081e4
&y2: 0x7fff5fbff76c
&y3: 0x7fff5fbff768
&x0: 0x10010a588
&x1: 0x10010a58c
------- on thread 2 -------
&y0: 0x1000e5d9c
&y1: 0x1000e5d98
&x0: 0x1001081e0
&x1: 0x1001081e4
&y2: 0x1000e5dfc
&y3: 0x1000e5df8
&x0: 0x10010a588
&x1: 0x10010a58c
&y4: 0x1000e5e6c
&y5: 0x1000e5e68
&x0: 0x10010a5e8
&x1: 0x10010a5ec

当 block 在主线程上执行时,它位于堆栈中(如本地变量和导入变量的地址所示)。当通过 dispatch_async 执行时,运行时复制了 block - 包括内部 block ,从 block 的本地变量和导入变量的地址可以看出。

我们可以在copy_helper_block函数处设置一个断点,实际上,程序会停在那里一次,以便将 block vv复制到堆中。

enter image description here

关于ios - dispatch_async 是否复制内部 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18157360/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com