oc 内存

iOS内存由高到低依次是:栈区->堆区->全局区/静态区->常量区->代码区

栈区的内存地址一般是0x7开头的;
堆区地址一般是0x6开头的;
全局区/静态区和常量区一般是0x1开头的;

1、栈区(stack heap) 栈区是由编译器自动分配并释放的;存放局部变量,函数的参数,例如函数的隐藏参数(id self,SEL _cmd)当离开作用域时,系统会自动销毁;栈区地址分配是从高地址到低地址,遵循先进后出,且内存是连续的;

2、堆区(heap) 存储动态分配的内存,alloc、malloc、new ,这种程序员手动分配的内存,这些内存也需要程序员自己管理;堆区地址分配是从低地址到高地址,遵循先进先出,且内存不连续(是以链表的形式存储,跟安卓的Hashmap原理一样,以空间换时间);

3、全局区、静态区 bss段( bss segment ) 存放未初始化的全局变量和静态变量

4、数据区、常量区(data segment) 一般存放已经初始化的全局变量和静态变量、常量(包括一些字符串常量、基本数据等)(编译器已经处理好的)

5、代码区(code segment/text segment) 存放程序员写的代码(二进制数据),main()函数中的demo。

1、栈区(stack heap) 栈区是由编译器自动分配并释放的;存放局部变量,函数的参数,例如函数的隐藏参数(id self,SEL _cmd)当离开作用域时,系统会自动销毁;栈区地址分配是从高地址到低地址,遵循先进后出,且内存是连续的;

2、堆区(heap) 存储动态分配的内存,alloc、malloc、new ,这种程序员手动分配的内存,这些内存也需要程序员自己管理;堆区地址分配是从低地址到高地址,遵循先进先出,且内存不连续(是以链表的形式存储,跟安卓的Hashmap原理一样,以空间换时间);

3、全局区、静态区 bss段( bss segment ) 存放未初始化的全局变量和静态变量

4、数据区、常量区(data segment) 一般存放已经初始化的全局变量和静态变量、常量(包括一些字符串常量、基本数据等)(编译器已经处理好的)

5、代码区(code segment/text segment) 存放程序员写的代码(二进制数据),main()函数中的demo。

上Demo分析:

#import “ViewController.h”
#import “Person.h”

NSString *gloabal = @“999”;
NSString *const gloabalConst = @“888”;

@implementation ViewController

  • (void)viewDidLoad {
    [super viewDidLoad];

    [self stackText];
    [self heapText];
    [self staticText];
    [self staticText];
    [self constTest];
    [self tagPointerTest];
    [self methodPass];
    }

//栈

  • (void)stackText
    {
    int a = 1;
    NSString *b = [NSString stringWithFormat:@“abc”];
    NSLog(@“a = %p , %p” , a , &a);
    NSLog(@“b = %p , %p” , b , &b);

// 在说栈内存前先说一下oc中的变量;
// 变量有三部分组成:1、变量名 2、变量类型 3、变量值; 变量的地址仅仅是它本身在内存中地址,而非该变量所指向对象(或所存储值)的内存地址;
// 例如:上面的a是一个int类型(基本数据类型)的变量,他的变量值是123;
// b是一个指针变量(NSString *), 它里面存储的是@“abc”字符串对象的地址。
// 指针地址:是储存指针或者变量所在内存中的地址,仅仅代表变量或者指针本身,而不能代表它们所指向的值。
// 指针变量:把指针变量拆分为指针和变量,指针表示指针变量所储存的是一个指针地址,变量表示指针变量所存储的地址会发生改变

// a = 0x1 , 0x7ffee939613c
// c = 0x600002be2da0 , 0x7ffee9396128

// 由上打印结果可见:
// a、b 变量的内存地址都在栈区(由于它们的都是局部变量)
// a变量存储的1,1的内存在常量区;
// b指针指向的@“abc”对象内存在堆区,因为该对象是通过alloc开辟的内存空间(@“abc”是一个对象,因为他有@);

}

//堆

  • (void)heapText
    {
    UIView *view = [[UIView alloc] init];
    UILabel *label = [[UILabel alloc] init];
    UIImageView *imageView = [[UIImageView alloc] init];
    NSObject *obj = [[NSObject alloc] init];
    UIImage *image = [[UIImage alloc] init];
    Person *person = [[Person alloc] init];
    NSArray *array = @[@“1” , @“2”];

    NSLog(@“view = %@ , %p” , view , &view);
    NSLog(@“label = %@ , %p” , label , &label);
    NSLog(@“imageView = %@ , %p” , imageView , &imageView);
    NSLog(@“obj = %p , %p” , obj , &obj);
    NSLog(@“image = %p , %p” , image , &image);
    NSLog(@“person = %p , %p” , person , &person);
    NSLog(@“array = %p , %p” , array , &array);

// 打印结果:
// view = <UIView: 0x7fce02405f80; frame = (0 0; 0 0); layer = <CALayer: 0x600002ef20c0>> , 0x7ffee5404120
// label = <UILabel: 0x7fce024062f0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x600000df00a0>> , 0x7ffee5404118
// imageView = <UIImageView: 0x7fce04b0a450; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x600002eb8b00>> , 0x7ffee5404110
// obj = 0x600002cec460 , 0x7ffee5404108
// image = 0x600001cec5a0 , 0x7ffee5404100
// person = 0x600002cec480 , 0x7ffee54040f8

//由打印结果可见,NSObject alloc的对象内存在堆区(UIView、UILabel、UIImageView本身打印的地址显示在栈区,但是它们的layer在堆区,这里个人猜测,“仅代表个人想法” UIView最终只是将layer展示在图层上,所以只是将layer放在了堆区?),而指针变量的内存都在栈区;
//栈区地址分配是编译器自动分配的,地址从高到低,且内存分配是连续的
//堆区地址是程序员手动分配的(arc环境下,编译器替代了程序员手动分配的工作)地址从低到高 ,且内存分配不是连续的(链表形式,跟安卓的Hashmap原理一样)

}

//全局/静态区

  • (void)staticText
    {
    static NSString *e;
    static NSString *f = @“111”;
    NSLog(@“e = %p , %p” , e , &e);
    NSLog(@“f = %p , %p” , f , &f);

    e = @“234”;
    f = @“345”;
    NSLog(@“e = %p , %p” , e , &e);
    NSLog(@“f = %p , %p” , f , &f);
    NSLog(@“gloabal = %p , %p” , gloabal , &gloabal);
    // staticText 连续执行两次 打印结果:
    // e = 0x0 , 0x10cf197d0
    // f = 0x10cf140e8 , 0x10cf19648
    // e = 0x10cf14148 , 0x10cf197d0
    // f = 0x10cf14168 , 0x10cf19648
    // gloabal = 0x107b9e028 , 0x107ba3640
    // e = 0x10cf14148 , 0x10cf197d0
    // f = 0x10cf14168 , 0x10cf19648
    // e = 0x10cf14148 , 0x10cf197d0
    // f = 0x10cf14168 , 0x10cf19648
    // gloabal = 0x107b9e028 , 0x107ba3640

// 从打印结果可见;静态变量e和f指针的地址始终没变,所以静态变量本身只会初始化一次,它的内存地址是不变的;但是静态变量指向或存储的值是可以变的;
// 没初始化的静态变量和全局变量地址是在全局区/静态区,已初始化的静态变量和全局变量是在常量/数据区

}

//常量

  • (void)constTest
    {
    NSString *const part = @“333”;
    NSLog(@“part = %p , %p” , part , &part);
    NSLog(@“gloabalConst = %p , %p” , gloabalConst , &gloabalConst);

// 打印结果
// part = 0x1002911d0 , 0x7ffeef96f138
// gloabalConst = 0x100291050 , 0x100291028

// 这里 part 是一个局部常量 gloabalConst 是一个全局常量;
// 由上面打印结果可见:
// 局部常量和局部变量的内存地址都在栈区;
// 全局常量和全局变量的内存地址都在全局区;

}

  • (void)tagPointerTest
    {
    NSNumber *number = @1;
    NSString *a = @“a”;
    NSString *b = [[NSString alloc] initWithString:@“e”];
    NSString *c = [NSString stringWithFormat:@“f”];
    NSString *d = [[NSMutableString alloc] initWithString:@“g”];
    NSString *e = [NSString stringWithFormat:@“i”];

    NSLog(@“number = %p , %p” , number , &number);
    NSLog(@“a = %p , %p” , a , &a);
    NSLog(@“b = %p , %p” , b , &b);
    NSLog(@“c = %p , %p” , c , &c);
    NSLog(@“d = %p , %p” , d , &d);
    NSLog(@“e = %p , %p” , e , &e);

// 打印结果:
// number = 0x9e88f04cad0fc5be , 0x7ffee53d4138
// a = 0x10a82c310 , 0x7ffee53d4130
// b = 0x10a82c330 , 0x7ffee53d4128
// c = 0x8e88f04cad0fc3cd , 0x7ffee53d4120
// d = 0x600001e488d0 , 0x7ffee53d4118
// e = 0x8e88f04cad0fc33d , 0x7ffee53d4110

// 从打印结果看,number、c、e 所存储的东西不是一个真正的指针地址,而是tagged pointer类型
// a、b 都是指向一个字符串常量,它的地址存在常量区;
// d 指向的字符串对象地址在堆区;

// 类型
// __NSCFConstantString :

  1. 常量字符串,存储在字符串常量区,继承于 __NSCFString。相同内容的 __NSCFConstantString 对象的地址相同,也就是说常量字符串对象是一种单例,可以通过== 判断字符串内容是否相同。
  2. 这种对象一般通过字面值@"…"创建。如果使用__NSCFConstantString 来初始化一个字符串,那么这个字符串也是相同的 __NSCFConstantString。
    // __NSCFString :
  3. 存储在堆区,需要维护其引用计数,继承于NSMutableString。
  4. 通过stringWithFormat:等方法创建的NSString对象(且字符串值过大无法使用Tagged Pointer存储)一般都是这种类型。
    // NSTaggedPointerString:
    Tagged Pointer,字符串的值直接存储在了指针上。

// Tagged Pointer:
// Tagged Pointer 是用于优化NSNumber、NSDate、NSString等小对象的存储;是将对象的值直接存储到指针中;
// Tagged Pointer 详细看链接:https://www.jianshu.com/p/7167c3fe21d0(转载)

}

//另:成员变量的内存是在堆区,因为oc对象实质上是一个结构体,对象是malloc开的空间,对象在堆区,而成员变量是对象的结构体内其中某个成员,所以成员变量跟对象一起在堆区。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值