对象在内存中的存储
栈(stack):用来存储程序的局部变量(但不包括static声明的变量,static修饰的数据存放于数据段中)。除此之外,在函数被调用时,栈用来传递参数和返回值。相当于在{}中声明的变量.
堆(heap):用于存储程序运行中被动态分配的内存段,它的大小并不固定,可动态的扩张和缩减。操作函数(malloc/free)
BSS段(bss segment):通常用来存储程序中未被初始化的全局变量和静态变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段输入静态内存分配
数据段(data segment):通常用来存储程序中已被初始化的全局变量和静态变量和字符串的一块内存区域
代码段(code segment):通常是指用来存储程序可执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量。
内存图oc 中没有垃圾回收机制,arc虽然可以管理内存,不需要程序员手动reatain release, 但是arc 管理不了循环引用的问题. 但是mac 中有垃圾回收机制.java中有垃圾回收机制,也不需要程序员手动管理内存.
但是oc 中也会出现野指针的问题.但是这个问题,不是oc的问题,是程序员没有把已经释放内存的指针置nil.
接下来,研究一下,对象在内存中如何存储
Person *p = [Person new];
这段话在内存中表示为:
p的内存分配new底层做的事情:
1.在堆内存中申请1块合适大小的空间
2.在这块内存上根据类模版创建对象。类模版中定义了什么属性就依次把这些属性声明在对象中;对象中还存在一个属性叫做isa,是一个指针,指向对象所属的类在代码段中地址
3.初始化对象的属性。这里初始化有几个原则:a、如果属性的数据类型是基本数据类型则赋值为0;b、如果属性的数据类型是C语言的指针类型则赋值为NULL;c、如果属性的数据类型为OC的指针类型则赋值为nil。
4.返回栈空间上对象的地址
注意
1.对象只有属性,没有方法。包括类本身的属性和一个指向代码段中的类isa指针
2.如何访问对象的属性?指针名->属性名;本质:根据指针名找到指针指向的对象,再根据属性名查找来访问对象的属性值
3.如何调用方法?[指针名 方法];本质:根据指针名找到指针指向的对象,再发现对象需要调用方法,再通过对象的isa指针找到代码段中的类,再调用类里面方法
4.为什么不把方法存储在对象中?
因为以类为模版创建的对象只有属性可能不相同,而方法相同,如果堆区的对象里面也保存方法的话就会很重复,浪费了堆空间,因此将方法存储与代码段
所以一个类创建的n个对象的isa指针的地址值都相同,都指向代码段中的类地址.
所以:
Person *p1 = [Person new];
Person *p2 = [Person new];
Person *p3 = [Person new];
p1 p2 p3 是3个不同的内存地址,但是p1 p2 p3 的isa指针地址都是一样的, 因为它们的isa指针 都是指向类Person 的代码区域.