区块链技术博客
www.b2bchain.cn

iOS 内存管理求职学习资料

本文介绍了iOS 内存管理求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

内存

虚拟内存

虚拟内存技术可以使一个应用程序认为自己有一段连续的内存空间(多个大小相同的内存页page组成的逻辑地址空间),使得程序编写和运行起来容易;同时隐藏了真实的物理内存地址,起到一定的保护作用;还能隔离不同的进程,更安全

当前虚拟内存和物理内存的分页都是16KB

iOS虚拟内存

内存空间结构

iOS 内存管理

因为iPhone中的磁盘用的是闪存(容量和读写寿命都有限制),所以iOS中没有memory swap机制,memory swap也就是当内存空间不足时将部分内存数据存储到磁盘中,等到下次使用时再从磁盘读取数据到内存中

取而代之的是,iOS采用的是内存警告memory warning,当系统检测到内存空间不足时,会给每个进程APP发送memory warning,在iOS中有代理方法来接收memory warning:

//UIViewController.h - (void)didReceiveMemoryWarning {     NSLog(@"%s",__FUNCTION__); } //UIApplication.h - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {     NSLog(@"%s",__FUNCTION__); }

模拟器可以通过Debug->simulate memory warning来发出memory warning

但这样的模拟memory warning并不会terminate app,实际的memory warning应该会terminate app

Clean Memory & Dirty Memory

Memory Page 分为 Clean Memory 和 Dirty Memory,前者通常来说是指能够进行memory swap的memory page,而后者不能够进行内存置换操作,但是iOS因为没有memory swap,所以Clean Memory不是通常的意思,在iOS中是指能够重复被使用的内存页,相对的,Dirty Memory是不能够重复使用的内存页

Clean Memory 主要包括以下几部分:

  1. app 的二进制可执行文件
  2. framework 中的 _DATA_CONST 段
  3. 文件映射的内存
  4. 未写入数据的内存

下面就“未写入数据的内存”举个例子:

int *array = malloc(20000 * sizeof(int)); array[0] = 32 array[19999] = 64

那么内存页分类如下:
iOS 内存管理

红色的页是 Dirty Memory,蓝色的页是Clean Memory

MRC

MRC就是手动加retain release autorelease,ARC就是编辑器帮你加retain release autorelease,下面测试下MRC:

首先关闭Xcode的ARC,在target->building phases->compile sources->选择要使用MRC的源文件->-fno-objc-arc

然后测试:

    NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     NSObject *obj2 = obj1.retain;     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 release];     NSLog(@"retain count:%ld",obj1.retainCount);

输出:

2020-08-14 15:01:19.235030+0800 APMDemo[26433:4385969] retain count:1 2020-08-14 15:01:19.235144+0800 APMDemo[26433:4385969] retain count:2 2020-08-14 15:01:19.235216+0800 APMDemo[26433:4385969] retain count:1

但是如果是这样:

    NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     NSObject *obj2 = obj1; // 这里不一样     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 release];     NSLog(@"retain count:%ld",obj1.retainCount);

输出:

2020-08-14 15:09:35.643069+0800 APMDemo[28334:4396744] retain count:1 2020-08-14 15:09:35.643206+0800 APMDemo[28334:4396744] retain count:1 然后报错了: EXC_BAD_ACCESS,因为指针直接赋值并不会使引用计数+1,所以release完引用计数变为0被回收了,所以会出现访问野指针报错

MRC的基本原则是,谁retain谁release

retain/release都比较好理解,下面重点讲一下autorelease

AutoRelease

Autorelease部分主要参考了这篇博客,但他关于自动释放池的本质部分不太正确,后面就没有参考

autorelease指的是自动释放,当一个对象收到autorelease的时候,该对象就会被注册到当前处于栈顶的自动释放池(autorelease pool)。如果没有主动生成自动释放池,则当前自动释放池对应的是当前runloop的自动释放池,在当前线程的RunLoop进入休眠前,就会对被注册到该自动释放池的所有对象进行一次release操作,举个例子:

    NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 autorelease];     NSLog(@"retain count:%ld",obj1.retainCount);

输出:

2020-08-14 15:23:13.545569+0800 APMDemo[29592:4410493] retain count:1 2020-08-14 15:23:13.545646+0800 APMDemo[29592:4410493] retain count:1

这是因为obj1在autorelease后注册到了的runloop的autoreleasePool,而释放池还没有释放对象(runloop的释放池会在beforeWaiting时统一drain,下面会讲),所以retainCount都是1

autorelease可以说是将“谁retain谁release”的原则打破,将对象的生命的所有权交给了autoreleasePool,由autoreleasePool负责release

下面再给自定义自动释放池的例子:

    NSAutoreleasePool *pool = [NSAutoreleasePool new];     NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 autorelease];     NSLog(@"retain count:%ld",obj1.retainCount);     [pool drain];     NSLog(@"retain count:%ld",obj1.retainCount);

这时输出:

2020-08-14 15:09:35.643069+0800 APMDemo[28334:4396744] retain count:1 2020-08-14 15:09:35.643206+0800 APMDemo[28334:4396744] retain count:1 然后报错了: EXC_BAD_ACCESS

这是因为栈顶的自动释放池不是runloop的释放池了,而是新建的释放池,自己定义的释放池就可以自己控制drain,当drain后池内的所有对象的retainCount都-1,所以当最后又访问了野指针。

上面只是个简单的demo,下面再举个autorelease解决实际问题的场景:

    NSObject *realObj1 = [[self obj1] retain];     NSLog(@"retain count:%ld",realObj1.retainCount); // 输出2,realObj1只能-1,导致真正的对象无法释放     NSObject *realObj2 = [[self obj2] retain];     NSLog(@"retain count:%ld",realObj2.retainCount); // 这行就崩溃了,访问了野指针     return YES; }  - (NSObject *)obj1 {     NSObject *_obj = [NSObject new];      return _obj; }  - (NSObject *)obj2 {     NSObject *_obj = [NSObject new];     [_obj release];     return _obj; }

autorelease就可以解决上述问题:

- (NSObject *)obj1 {     NSObject *_obj = [NSObject new];     [_obj autorelease];     return _obj; }

MRC 和 ARC 区别

MRC比较实在,就是指针引用加上引用计数,举个例子(MRC环境):

    NSObject *obj = [NSObject new];     NSLog(@"retain count:%ld",obj.retainCount);     {         NSObject *obj2 = obj.retain;         NSLog(@"retain count:%ld",obj.retainCount);     }     NSLog(@"retain count:%ld",obj.retainCount);

输出1 2 2,因为new和大括号里的retain+1,但是并没有release,所以后两个计数是2

但在ARC环境下:

    NSObject *obj = [NSObject new];     NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));     {         NSObject *obj2 = obj;         NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));     }     NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));

输出得1 2 1,这是因为大括号里的obj2默认是__strong修饰符,所以引用计数+1,但当大括号结束,obj2生命周期也结束了,所以它会释放掉对obj的引用,致使obj的引用计数-1

@autoreleasepool{}在MRC和ARC

OOM

大致上,OOM是当系统内存不足时,系统强杀占内存高、优先级低的进程,分为FOOM和BOOM-前台强杀和后台强杀,而FOOM更严重,和Crash无异

Mach-O

以下内容参考自这篇文章

Mach-O就是苹果系统中的可执行文件的格式,下面找一个Mach-O文件来看一下:

Xcode的文件目录Productsxxx.app右键show in finder,然后命令行进入该目录,并进入xxx子目录下(显示包内容)会发现有个xxx的可执行文件,在命令行file xxx,便会看到以下内容:

HookDemo: Mach-O 64-bit executable x86_64

内存

虚拟内存

虚拟内存技术可以使一个应用程序认为自己有一段连续的内存空间(多个大小相同的内存页page组成的逻辑地址空间),使得程序编写和运行起来容易;同时隐藏了真实的物理内存地址,起到一定的保护作用;还能隔离不同的进程,更安全

当前虚拟内存和物理内存的分页都是16KB

iOS虚拟内存

内存空间结构

iOS 内存管理

因为iPhone中的磁盘用的是闪存(容量和读写寿命都有限制),所以iOS中没有memory swap机制,memory swap也就是当内存空间不足时将部分内存数据存储到磁盘中,等到下次使用时再从磁盘读取数据到内存中

取而代之的是,iOS采用的是内存警告memory warning,当系统检测到内存空间不足时,会给每个进程APP发送memory warning,在iOS中有代理方法来接收memory warning:

//UIViewController.h - (void)didReceiveMemoryWarning {     NSLog(@"%s",__FUNCTION__); } //UIApplication.h - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {     NSLog(@"%s",__FUNCTION__); }

模拟器可以通过Debug->simulate memory warning来发出memory warning

但这样的模拟memory warning并不会terminate app,实际的memory warning应该会terminate app

Clean Memory & Dirty Memory

Memory Page 分为 Clean Memory 和 Dirty Memory,前者通常来说是指能够进行memory swap的memory page,而后者不能够进行内存置换操作,但是iOS因为没有memory swap,所以Clean Memory不是通常的意思,在iOS中是指能够重复被使用的内存页,相对的,Dirty Memory是不能够重复使用的内存页

Clean Memory 主要包括以下几部分:

  1. app 的二进制可执行文件
  2. framework 中的 _DATA_CONST 段
  3. 文件映射的内存
  4. 未写入数据的内存

下面就“未写入数据的内存”举个例子:

int *array = malloc(20000 * sizeof(int)); array[0] = 32 array[19999] = 64

那么内存页分类如下:
iOS 内存管理

红色的页是 Dirty Memory,蓝色的页是Clean Memory

MRC

MRC就是手动加retain release autorelease,ARC就是编辑器帮你加retain release autorelease,下面测试下MRC:

首先关闭Xcode的ARC,在target->building phases->compile sources->选择要使用MRC的源文件->-fno-objc-arc

然后测试:

    NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     NSObject *obj2 = obj1.retain;     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 release];     NSLog(@"retain count:%ld",obj1.retainCount);

输出:

2020-08-14 15:01:19.235030+0800 APMDemo[26433:4385969] retain count:1 2020-08-14 15:01:19.235144+0800 APMDemo[26433:4385969] retain count:2 2020-08-14 15:01:19.235216+0800 APMDemo[26433:4385969] retain count:1

但是如果是这样:

    NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     NSObject *obj2 = obj1; // 这里不一样     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 release];     NSLog(@"retain count:%ld",obj1.retainCount);

输出:

2020-08-14 15:09:35.643069+0800 APMDemo[28334:4396744] retain count:1 2020-08-14 15:09:35.643206+0800 APMDemo[28334:4396744] retain count:1 然后报错了: EXC_BAD_ACCESS,因为指针直接赋值并不会使引用计数+1,所以release完引用计数变为0被回收了,所以会出现访问野指针报错

MRC的基本原则是,谁retain谁release

retain/release都比较好理解,下面重点讲一下autorelease

AutoRelease

Autorelease部分主要参考了这篇博客,但他关于自动释放池的本质部分不太正确,后面就没有参考

autorelease指的是自动释放,当一个对象收到autorelease的时候,该对象就会被注册到当前处于栈顶的自动释放池(autorelease pool)。如果没有主动生成自动释放池,则当前自动释放池对应的是当前runloop的自动释放池,在当前线程的RunLoop进入休眠前,就会对被注册到该自动释放池的所有对象进行一次release操作,举个例子:

    NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 autorelease];     NSLog(@"retain count:%ld",obj1.retainCount);

输出:

2020-08-14 15:23:13.545569+0800 APMDemo[29592:4410493] retain count:1 2020-08-14 15:23:13.545646+0800 APMDemo[29592:4410493] retain count:1

这是因为obj1在autorelease后注册到了的runloop的autoreleasePool,而释放池还没有释放对象(runloop的释放池会在beforeWaiting时统一drain,下面会讲),所以retainCount都是1

autorelease可以说是将“谁retain谁release”的原则打破,将对象的生命的所有权交给了autoreleasePool,由autoreleasePool负责release

下面再给自定义自动释放池的例子:

    NSAutoreleasePool *pool = [NSAutoreleasePool new];     NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 autorelease];     NSLog(@"retain count:%ld",obj1.retainCount);     [pool drain];     NSLog(@"retain count:%ld",obj1.retainCount);

这时输出:

2020-08-14 15:09:35.643069+0800 APMDemo[28334:4396744] retain count:1 2020-08-14 15:09:35.643206+0800 APMDemo[28334:4396744] retain count:1 然后报错了: EXC_BAD_ACCESS

这是因为栈顶的自动释放池不是runloop的释放池了,而是新建的释放池,自己定义的释放池就可以自己控制drain,当drain后池内的所有对象的retainCount都-1,所以当最后又访问了野指针。

上面只是个简单的demo,下面再举个autorelease解决实际问题的场景:

    NSObject *realObj1 = [[self obj1] retain];     NSLog(@"retain count:%ld",realObj1.retainCount); // 输出2,realObj1只能-1,导致真正的对象无法释放     NSObject *realObj2 = [[self obj2] retain];     NSLog(@"retain count:%ld",realObj2.retainCount); // 这行就崩溃了,访问了野指针     return YES; }  - (NSObject *)obj1 {     NSObject *_obj = [NSObject new];      return _obj; }  - (NSObject *)obj2 {     NSObject *_obj = [NSObject new];     [_obj release];     return _obj; }

autorelease就可以解决上述问题:

- (NSObject *)obj1 {     NSObject *_obj = [NSObject new];     [_obj autorelease];     return _obj; }

MRC 和 ARC 区别

MRC比较实在,就是指针引用加上引用计数,举个例子(MRC环境):

    NSObject *obj = [NSObject new];     NSLog(@"retain count:%ld",obj.retainCount);     {         NSObject *obj2 = obj.retain;         NSLog(@"retain count:%ld",obj.retainCount);     }     NSLog(@"retain count:%ld",obj.retainCount);

输出1 2 2,因为new和大括号里的retain+1,但是并没有release,所以后两个计数是2

但在ARC环境下:

    NSObject *obj = [NSObject new];     NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));     {         NSObject *obj2 = obj;         NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));     }     NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));

输出得1 2 1,这是因为大括号里的obj2默认是__strong修饰符,所以引用计数+1,但当大括号结束,obj2生命周期也结束了,所以它会释放掉对obj的引用,致使obj的引用计数-1

@autoreleasepool{}在MRC和ARC

OOM

大致上,OOM是当系统内存不足时,系统强杀占内存高、优先级低的进程,分为FOOM和BOOM-前台强杀和后台强杀,而FOOM更严重,和Crash无异

Mach-O

以下内容参考自这篇文章

Mach-O就是苹果系统中的可执行文件的格式,下面找一个Mach-O文件来看一下:

Xcode的文件目录Productsxxx.app右键show in finder,然后命令行进入该目录,并进入xxx子目录下(显示包内容)会发现有个xxx的可执行文件,在命令行file xxx,便会看到以下内容:

HookDemo: Mach-O 64-bit executable x86_64

内存

虚拟内存

虚拟内存技术可以使一个应用程序认为自己有一段连续的内存空间(多个大小相同的内存页page组成的逻辑地址空间),使得程序编写和运行起来容易;同时隐藏了真实的物理内存地址,起到一定的保护作用;还能隔离不同的进程,更安全

当前虚拟内存和物理内存的分页都是16KB

iOS虚拟内存

内存空间结构

iOS 内存管理

因为iPhone中的磁盘用的是闪存(容量和读写寿命都有限制),所以iOS中没有memory swap机制,memory swap也就是当内存空间不足时将部分内存数据存储到磁盘中,等到下次使用时再从磁盘读取数据到内存中

取而代之的是,iOS采用的是内存警告memory warning,当系统检测到内存空间不足时,会给每个进程APP发送memory warning,在iOS中有代理方法来接收memory warning:

//UIViewController.h - (void)didReceiveMemoryWarning {     NSLog(@"%s",__FUNCTION__); } //UIApplication.h - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {     NSLog(@"%s",__FUNCTION__); }

模拟器可以通过Debug->simulate memory warning来发出memory warning

但这样的模拟memory warning并不会terminate app,实际的memory warning应该会terminate app

Clean Memory & Dirty Memory

Memory Page 分为 Clean Memory 和 Dirty Memory,前者通常来说是指能够进行memory swap的memory page,而后者不能够进行内存置换操作,但是iOS因为没有memory swap,所以Clean Memory不是通常的意思,在iOS中是指能够重复被使用的内存页,相对的,Dirty Memory是不能够重复使用的内存页

Clean Memory 主要包括以下几部分:

  1. app 的二进制可执行文件
  2. framework 中的 _DATA_CONST 段
  3. 文件映射的内存
  4. 未写入数据的内存

下面就“未写入数据的内存”举个例子:

int *array = malloc(20000 * sizeof(int)); array[0] = 32 array[19999] = 64

那么内存页分类如下:
iOS 内存管理

红色的页是 Dirty Memory,蓝色的页是Clean Memory

MRC

MRC就是手动加retain release autorelease,ARC就是编辑器帮你加retain release autorelease,下面测试下MRC:

首先关闭Xcode的ARC,在target->building phases->compile sources->选择要使用MRC的源文件->-fno-objc-arc

然后测试:

    NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     NSObject *obj2 = obj1.retain;     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 release];     NSLog(@"retain count:%ld",obj1.retainCount);

输出:

2020-08-14 15:01:19.235030+0800 APMDemo[26433:4385969] retain count:1 2020-08-14 15:01:19.235144+0800 APMDemo[26433:4385969] retain count:2 2020-08-14 15:01:19.235216+0800 APMDemo[26433:4385969] retain count:1

但是如果是这样:

    NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     NSObject *obj2 = obj1; // 这里不一样     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 release];     NSLog(@"retain count:%ld",obj1.retainCount);

输出:

2020-08-14 15:09:35.643069+0800 APMDemo[28334:4396744] retain count:1 2020-08-14 15:09:35.643206+0800 APMDemo[28334:4396744] retain count:1 然后报错了: EXC_BAD_ACCESS,因为指针直接赋值并不会使引用计数+1,所以release完引用计数变为0被回收了,所以会出现访问野指针报错

MRC的基本原则是,谁retain谁release

retain/release都比较好理解,下面重点讲一下autorelease

AutoRelease

Autorelease部分主要参考了这篇博客,但他关于自动释放池的本质部分不太正确,后面就没有参考

autorelease指的是自动释放,当一个对象收到autorelease的时候,该对象就会被注册到当前处于栈顶的自动释放池(autorelease pool)。如果没有主动生成自动释放池,则当前自动释放池对应的是当前runloop的自动释放池,在当前线程的RunLoop进入休眠前,就会对被注册到该自动释放池的所有对象进行一次release操作,举个例子:

    NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 autorelease];     NSLog(@"retain count:%ld",obj1.retainCount);

输出:

2020-08-14 15:23:13.545569+0800 APMDemo[29592:4410493] retain count:1 2020-08-14 15:23:13.545646+0800 APMDemo[29592:4410493] retain count:1

这是因为obj1在autorelease后注册到了的runloop的autoreleasePool,而释放池还没有释放对象(runloop的释放池会在beforeWaiting时统一drain,下面会讲),所以retainCount都是1

autorelease可以说是将“谁retain谁release”的原则打破,将对象的生命的所有权交给了autoreleasePool,由autoreleasePool负责release

下面再给自定义自动释放池的例子:

    NSAutoreleasePool *pool = [NSAutoreleasePool new];     NSObject *obj1 = [NSObject new];     NSLog(@"retain count:%ld",obj1.retainCount);     [obj1 autorelease];     NSLog(@"retain count:%ld",obj1.retainCount);     [pool drain];     NSLog(@"retain count:%ld",obj1.retainCount);

这时输出:

2020-08-14 15:09:35.643069+0800 APMDemo[28334:4396744] retain count:1 2020-08-14 15:09:35.643206+0800 APMDemo[28334:4396744] retain count:1 然后报错了: EXC_BAD_ACCESS

这是因为栈顶的自动释放池不是runloop的释放池了,而是新建的释放池,自己定义的释放池就可以自己控制drain,当drain后池内的所有对象的retainCount都-1,所以当最后又访问了野指针。

上面只是个简单的demo,下面再举个autorelease解决实际问题的场景:

    NSObject *realObj1 = [[self obj1] retain];     NSLog(@"retain count:%ld",realObj1.retainCount); // 输出2,realObj1只能-1,导致真正的对象无法释放     NSObject *realObj2 = [[self obj2] retain];     NSLog(@"retain count:%ld",realObj2.retainCount); // 这行就崩溃了,访问了野指针     return YES; }  - (NSObject *)obj1 {     NSObject *_obj = [NSObject new];      return _obj; }  - (NSObject *)obj2 {     NSObject *_obj = [NSObject new];     [_obj release];     return _obj; }

autorelease就可以解决上述问题:

- (NSObject *)obj1 {     NSObject *_obj = [NSObject new];     [_obj autorelease];     return _obj; }

MRC 和 ARC 区别

MRC比较实在,就是指针引用加上引用计数,举个例子(MRC环境):

    NSObject *obj = [NSObject new];     NSLog(@"retain count:%ld",obj.retainCount);     {         NSObject *obj2 = obj.retain;         NSLog(@"retain count:%ld",obj.retainCount);     }     NSLog(@"retain count:%ld",obj.retainCount);

输出1 2 2,因为new和大括号里的retain+1,但是并没有release,所以后两个计数是2

但在ARC环境下:

    NSObject *obj = [NSObject new];     NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));     {         NSObject *obj2 = obj;         NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));     }     NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));

输出得1 2 1,这是因为大括号里的obj2默认是__strong修饰符,所以引用计数+1,但当大括号结束,obj2生命周期也结束了,所以它会释放掉对obj的引用,致使obj的引用计数-1

@autoreleasepool{}在MRC和ARC

OOM

大致上,OOM是当系统内存不足时,系统强杀占内存高、优先级低的进程,分为FOOM和BOOM-前台强杀和后台强杀,而FOOM更严重,和Crash无异

Mach-O

以下内容参考自这篇文章

Mach-O就是苹果系统中的可执行文件的格式,下面找一个Mach-O文件来看一下:

Xcode的文件目录Productsxxx.app右键show in finder,然后命令行进入该目录,并进入xxx子目录下(显示包内容)会发现有个xxx的可执行文件,在命令行file xxx,便会看到以下内容:

HookDemo: Mach-O 64-bit executable x86_64

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » iOS 内存管理求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们