前面已经说过Block对基本类型变量的捕获,现在来看看Block对对象变量的捕获。先看看下面几个问题
1、对象的局部变量捕获和基本数据类型有点区别,对象的局部auto变量捕获是指针捕获不是值捕获,所以捕获的内容会受外部变量的影响
2、因为block捕获了auto变量所以block是NSStackBlock,在ARC下将block赋值给__strong指针时会自动将栈上的block复制到堆上,block由NSStackBlock变为NSMallocBlock
1、这里Person虽然是局部变量,但是不是在离开作用域时(离开大括号)被释放,因为Person在被block捕获时被block强引用了,引用计数加了1,只有当引用计数为0时才会被释放。当block调用完从堆上移除时,会调用block内部的dispose函数,dispose函数内部会调用_Block_object_dispose函数,_Block_object_dispose函数会自动释放引用的auto变量(release),person的引用计数减1,此时person的引用计数为0被释放
2、block为NSMallocBlock的原因与问题一一样,这里需要说的是,只有在NSMallocBlock下才会对auto变量产生强引用,如果block是在栈上,将不会对auto变量产生强引用。
如果block被拷贝到堆上,会调用block内部的copy函数,copy函数内部会调用_Block_object_assign函数,_Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的 *** 作,形成强引用(retain)或者弱引用
在问题二中有说到,堆上的Block会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的 *** 作,形成强引用(retain)或者弱引用。这里的person的修饰符为weak,所以block会对其产生弱引用,引用计数不会加1,当出作用域时person会被释放
1、self为对象局部auto变量,所以是指针捕获,内部的值会受外部的影响
2、block对self产生了一个强引用
Block变量捕获详解(一)
Block的三种类型(二)
__block修饰符(四)
Block循环引用(五)
以在linux下为例,适用gcc编译一个名为testc的文件,文件里面有个函数定义void test(void);
#include "stdioh"
void test(void)
{
printf("test!!!\n");
}
int main(int arg, void args[])
{
test();
return 0;
}
编译命令gcc -o test testc 生成test可执行文件。
用readelf -s test命令可以读出test文件里面的各个段的大小。
Symbol table 'dynsym' contains 6 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 401 FUNC GLOBAL DEFAULT UND puts@GLIBC_20 (2)
2: 00000000 391 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_20 (2)
3: 0804845c 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used
4: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
5: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Symbol table 'symtab' contains 71 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048114 0 SECTION LOCAL DEFAULT 1
2: 08048128 0 SECTION LOCAL DEFAULT 2
3: 08048148 0 SECTION LOCAL DEFAULT 3
4: 08048174 0 SECTION LOCAL DEFAULT 4
5: 080481d4 0 SECTION LOCAL DEFAULT 5
6: 08048232 0 SECTION LOCAL DEFAULT 6
7: 08048240 0 SECTION LOCAL DEFAULT 7
8: 08048260 0 SECTION LOCAL DEFAULT 8
9: 08048268 0 SECTION LOCAL DEFAULT 9
10: 08048280 0 SECTION LOCAL DEFAULT 10
11: 08048298 0 SECTION LOCAL DEFAULT 11
12: 080482d8 0 SECTION LOCAL DEFAULT 12
13: 0804843c 0 SECTION LOCAL DEFAULT 13
14: 08048458 0 SECTION LOCAL DEFAULT 14
15: 08048468 0 SECTION LOCAL DEFAULT 15
16: 0804946c 0 SECTION LOCAL DEFAULT 16
17: 08049474 0 SECTION LOCAL DEFAULT 17
18: 0804947c 0 SECTION LOCAL DEFAULT 18
19: 08049480 0 SECTION LOCAL DEFAULT 19
20: 08049548 0 SECTION LOCAL DEFAULT 20
21: 0804954c 0 SECTION LOCAL DEFAULT 21
22: 08049564 0 SECTION LOCAL DEFAULT 22
23: 08049570 0 SECTION LOCAL DEFAULT 23
24: 00000000 0 SECTION LOCAL DEFAULT 24
25: 00000000 0 SECTION LOCAL DEFAULT 25
26: 00000000 0 SECTION LOCAL DEFAULT 26
27: 00000000 0 SECTION LOCAL DEFAULT 27
28: 080482fc 0 FUNC LOCAL DEFAULT 12 call_gmon_start
29: 00000000 0 FILE LOCAL DEFAULT ABS crtstuffc
30: 0804946c 0 OBJECT LOCAL DEFAULT 16 __CTOR_LIST__
31: 08049474 0 OBJECT LOCAL DEFAULT 17 __DTOR_LIST__
32: 0804947c 0 OBJECT LOCAL DEFAULT 18 __JCR_LIST__
33: 08049570 1 OBJECT LOCAL DEFAULT 23 completed4583
34: 0804956c 0 OBJECT LOCAL DEFAULT 22 p4582
35: 08048320 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux
36: 08048354 0 FUNC LOCAL DEFAULT 12 frame_dummy
37: 00000000 0 FILE LOCAL DEFAULT ABS crtstuffc
38: 08049470 0 OBJECT LOCAL DEFAULT 16 __CTOR_END__
39: 08049478 0 OBJECT LOCAL DEFAULT 17 __DTOR_END__
40: 08048468 0 OBJECT LOCAL DEFAULT 15 __FRAME_END__
41: 0804947c 0 OBJECT LOCAL DEFAULT 18 __JCR_END__
42: 08048414 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux
43: 00000000 0 FILE LOCAL DEFAULT ABS testc
44: 08049480 0 OBJECT GLOBAL DEFAULT 19 _DYNAMIC
45: 08048458 4 OBJECT GLOBAL DEFAULT 14 _fp_hw
46: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __fini_array_end
47: 08049568 0 OBJECT GLOBAL HIDDEN 22 __dso_handle
48: 0804840c 5 FUNC GLOBAL DEFAULT 12 __libc_csu_fini
49: 00000000 401 FUNC GLOBAL DEFAULT UND puts@@GLIBC_20
50: 08048280 0 FUNC GLOBAL DEFAULT 10 _init
51: 0804837c 24 FUNC GLOBAL DEFAULT 12 test
52: 080482d8 0 FUNC GLOBAL DEFAULT 12 _start
53: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __fini_array_start
54: 080483bc 79 FUNC GLOBAL DEFAULT 12 __libc_csu_init
55: 08049570 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
56: 08048394 40 FUNC GLOBAL DEFAULT 12 main
57: 00000000 391 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
58: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __init_array_end
59: 08049564 0 NOTYPE WEAK DEFAULT 22 data_start
60: 0804843c 0 FUNC GLOBAL DEFAULT 13 _fini
61: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __preinit_array_end
62: 08049570 0 NOTYPE GLOBAL DEFAULT ABS _edata
63: 0804954c 0 OBJECT GLOBAL HIDDEN 21 _GLOBAL_OFFSET_TABLE_
64: 08049574 0 NOTYPE GLOBAL DEFAULT ABS _end
65: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __init_array_start
66: 0804845c 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used
67: 08049564 0 NOTYPE GLOBAL DEFAULT 22 __data_start
68: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
69: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __preinit_array_start
70: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
其中,
51: 0804837c 24 FUNC GLOBAL DEFAULT 12 test
这行0804837c就是test()函数的起始地址,24就是test()函数的指令静态存储空间。
弱引用:只要有对象引用,他就不会被垃圾回收。
介绍之前,不了解这些概念的同学可以参考一下以下链接。
WeakMap:weakMapset(ref, realData)这边针对的是对键的弱引用。可以理解为是向对象 ref 中添加值为 realData的内容,通过ref来获取realData, 一旦不再持有对象的引用,即使你仍持有添加了该对象的 WeakMap 的引用对象,也会被垃圾回收 。
WeakRef:允许您保留对另一个对象的弱引用,而不会阻止被弱引用对象被GC回收。-没有很理解
看下面这个图:
对WeakMap和WeakRef新的认识 :
FinalizationGroup API可以注册一个回调,以便在垃圾回收器回收已注册的对象时运行。可以手动写一个回调函数用来做垃圾回收。
weakRef弱引用
参考文章: https://blogcsdnnet/howgod/article/details/103727351
注意看这个文件
sysdeps/unix/sysv/linux/syscallslist
里面记录着系统调用的名字和一些属性,具体我也没有研究过,不懂。
再看select的实现,很让人惊讶,一旦使用,结果就是“报错“。
int
__select (nfds, readfds, writefds, exceptfds, timeout)
int nfds;
fd_set readfds;
fd_set writefds;
fd_set exceptfds;
struct timeval timeout;
{
__set_errno (ENOSYS);
return -1;
}
libc_hidden_def (__select)
stub_warning (select)
weak_alias (__select, select)
这是因为glibc并没有实现系统调用,而是调用系统调用,
更进一步,连调用系统调用都没有一个个实现,而是使用了通用的办法,
理由很简单,所有的系统调用在linux内核头文件里都能找到,
所有的系统调用参数类型就那么几种,参数个数也是有限的,
因此没有必要针对所有的系统调用一一封装,
于是就有了这个list文件,自动生成调用系统调用的函数,
如果生成失败,也就是你看到的“报错”。
符号是有强弱的,当自动生成成功的时候,“报错”的弱符号就被忽略了。
当你在glibc中找到一个系统调用的封装源码,是以下原因,
编译的目标系统不支持这个系统调用,所以自己用另一种方式实现了。
2 这个系统调用无法使用通用的自动生成方式生成,用特化的方式覆盖。
3 针对这个系统调用做了特别的优化。
4 其它可能的原因。
具体可以留意
SYSCALL, PSEUDO, DO_CALL, INLINE_CALL 等名字
这两个文件是重点所在
sysdeps/unix/i386/sysdeph
sysdeps/unix/i386/sysdepS
要搞清楚具体的自动生成过程,恐怕得研究glibc自身的编译过程了
这个问题是一个好问题,我之前也没思索过或者尝试过,
首先我们弄清楚一件事,函数声明可以放在任何头文件,实现可以放在任何实现该函数的源文件中,那么就存在一个问题:
编译时,到底优先去使用哪一个,为什么没有把标准库中的函数扩展过来;在windows下标准库被编译成了msvcr120dll(msvcr100dll,这里指release版),所以并不是扩展到代码中,而是在调用时动态链接;
而题主在其中自定义文件中实现了该函数,所以编译时找到了该函数的实现,并不会去链接dll(这应该是编译器做的一些工作,确定系统的dll需要加载哪些),所以题主的程序执行时就只有一份fputc了,并不冲突。
题主可以通过快捷键跳转声明就知道了,VS下,点选fputc实现函数按F12跳转到声明,指向的是stdioh,再按一次跳转到你自己的定义了。Qt的话使用F2。
大概就是这样子了,可追问。
常用词汇:
1、short:修饰int,短整型数据,可省略被修饰的int。
2、long:修饰int,长整型数据,可省略被修饰的int。
3、long long:修饰int,超长整型数据,可省略被修饰的int。
4、signed:修饰整型数据,有符号数据类型。
5、unsigned:修饰整型数据,无符号数据类型。
6、restrict:用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式。
7、return:用在函数体中,返回特定值(如果是void类型,则不返回函数值)。
8、continue:结束当前循环,开始下一轮循环。
9、break:跳出当前循环或switch结构。
10、goto:无条件跳转语句。
11、if:条件语句,后面不需要放分号。
12、else:条件语句否定分支(与if连用)。
13、switch:开关语句(多重分支语句)。
14、case:开关语句中的分支标记,与switch连用。
15、default:开关语句中的“其他”分支,可选。
常用函数:
1、int isalpha(int ch) 若ch是字母('A'-'Z','a'-'z'),返回非0值,否则返回0。
2、int isalnum(int ch) 若ch是字母('A'-'Z','a'-'z')或数字('0'-'9'),返回非0值,否则返回0。
3、int abs(int i) 返回整型参数i的绝对值。
4、double cabs(struct complex znum) 返回复数znum的绝对值。
5、double fabs(double x) 返回双精度参数x的绝对值。
6、long labs(long n) 返回长整型参数n的绝对值。
—C语言
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)