iOS开发技巧

OC底层原理18-多线程

2020-11-04  本文已影响0人  夏天的枫_

线程 & 进程

线程

进程

譬如Mac可以通过“活动监视器”查看系统中所开启的进程。

线程与进程的关系

  1. 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程奔溃会导致整个进程都死掉。所以多进程要比多线程健壮。
  2. 进程切换时,效率高,但消耗的资源大。所以涉及到频繁切换时,使用线程要比进程好。同样如果要同时进行并且又要共享某些变量的并发操作,只能用线程而不能用进程。
  3. 执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立运行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  4. 线程是处理器调度的基本单位,但进程不是。
  5. 线程没有地址空间,线程包含在进程的地址空间中。

安卓开发可以有多个进程;iOS往往是单进程。

多线程

多个线程在多CPU下时,效率是非常之高的,相比于一个CPU在一个进程中只能执行一条线程,现如今的多核CPU对多线程并发处理逻辑提供非常好的支持。但多线程也会有其优点和不足

优点

缺点

多线程 & CPU

内存区

进程、线程的执行都是需要依托内存去执行的,同一进程内的线程会共享本进程的内存。而「内存」会有多种,在iOS中分为:栈区、堆区、全局区(静态区)、常量区、代码区。接下来看看各自内存五大区都负责什么。

栈区(stack)

按照苹果文档介绍,辅助线程允许的最小堆栈大小为16 KB,并且堆栈大小必须为4 KB的倍数。在线程创建时会在进程空间中预留此内存的空间,但是直到需要它们时,才会创建与该内存关联的实际页面。这还取决于CPU负载,计算机速度以及可用系统和程序内存的数量。

内存创建空间需求

堆区(Heap)

通过下面的例子可以看看栈区地址和堆区地址的不同

// 定义一个Acount类
@interface Account()

@end
@implementation Account
- (void)printWithName:(NSString *)name
{
   // 参数name是一个指针,指向传入的参数指针所指向的对象内存地址。name是在栈中
  NSLog(@"name指针地址:%p,name指针指向的对象内存地址:%p",&name,name);
}

  /* account 是指针变量,在栈中;[Account alloc]开辟的内存空间就是在堆中
  *  account 指针指向了[[Account alloc]init]所创建的对象。
  */
  Account *account = [[Account alloc]init];

通过打印地址可以知道,传入参数的对象地址与print方法参数的对象指针地址不一样,但是内存地址是一样的,p account 打印的则是堆空间地址,一般以0x6开头,栈空间地址一般以0x7开头。

全局区(静态区)

静态变量有两种

优点:不管对象方法还是类方法都可以访问和修改全局静态变量,并且外部类无法调用静态变量,定义后只会指向固定的指针地址,供所有对象使用,节省空间。

缺点:存在的生命周期长,从定义直到程序结束。

建议:从内存优化和程序编译的角度来说,尽量少用全局静态变量,因为存在的声明周期长,一直占用空间。程序运行时会单独加载一次全局静态变量,过多的全局静态变量会造成程序启动慢。

优点:定义后只会存在一份值,每次调用都是使用的同一个对象内存地址的值,并没有重新创建,节省空间,只能在该局部代码块中使用。

缺点:存在的生命周期长,从定义直到程序结束,只能在该局部代码块中使用。

建议:局部和全局静态变量从根本意义上没有什么区别,只是作用域不同。如果值仅是一个类中的对象和类方法使用并且值可变,可以定义全局静态变量,如果是多个类使用并可变,建议值定义在model作为成员变量使用。如果是不可变值,建议使用宏定义 ,譬如:static NSString * value;

常量区(cosnt)

// .h中定义extern
extern NSString *const name;
// .m中定义值
NSString *const name = @"123";

代码区

内存五大区示意图


内存五大区
上一篇 下一篇

猜你喜欢

热点阅读