对象在内存中的存储
知识点:内存中的五大区域;类加载;对象在内存中是如何存储的。
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
@public
NSString *_name;
int _age;
int *p1;
}
- (void)selfInfo;
@end // Person
@implementation Person
- (void)selfInfo
{
NSLog(@"大家好,我是%@,今年%d岁啦~", _name, _age);
}
@end // person
int main(int argc, const char * argv[]) {
// 创建p1对象时,进行类加载;创建p2对象时不会
Person *p1 = [Person new];
//Person *p2 = [Person new];
p1->_name = @"Emun";
p1->_age = 20;
[p1 selfInfo];
NSLog(@"验证p1的值是否为地址:p1 = %p", p1);
return 0;
}
/*
对象在内存中的存储
1.内存中的五大区域
栈:存储局部变量
堆:程序员手动申请的字节空间;malloc calloc realloc函数
BSS段:存储未被初始化的全局变量,静态变量
数据段(常量区):存储已被初始化的全局变量,静态变量,常量数据
代码段:存储代码
2.类加载
1)在创建对象的时候,是需要访问类的
2)声明一个类的指针变量画也会访问类
在程序运行期间,当某个类第一次被访问到的时候,会将这个类存储到内存中的代码段区域,这个过程叫做类加载。
只有类在第一次被访问的时候,才会做类加载;一旦类被加载到代码段以后,直到程序结束才会被释放。
3.对象在内存中是如何存储的
首先在main函数中执行--Person *p1 = [Person new];
1)Person *p1 会在栈内存中申请一块空间,意思是在栈内存中声明一个Person类型的指针变量p1。(p1是一个指针变量,只能存储地址)
2)[Person new] 真正在内存中创建对象的是这串代码,new是一个方法,做的事情有:
a.在堆内存中申请一块合适大小的空间
b.在这个空间中根据类的模板创建对象(将类模板中定义的属性依次声明在对象之中)
对象中还会有另外一个属性,叫做 isa ,是一个指针,指向类模板在代码段中的地址
c.初始化类的属性
如果属性的类型是基本数据类型,那么就赋值为0
如果属性的类型是C语言的指针类型,那么就赋值为NULL
如果属性的类型是OC的类指针类型,那么就赋值为nil
d.返回对象的地址给p1指针
3)注意:
a.对象中只有属性(根据类模板声明的属性外加一个isa属性),而没有方法
b.访问对象的属性 指针名(对象名)->属性名 例:p1->_name = @"Emun";
过程:其实是根据p1指针中存储的地址找到对象,再找到对象中的属性来访问
c.调用方法 [指针名 方法名]; 例:[p1 selfInfo];
过程:先根据指针名找到对象,再根据对象中的 isa 属性找到类,再从类中调用方法
*/
调试并验证
首先来看一下控制台输出,验证p1存储的是否是个十六进制地址
Xcode添加断点调试验证对象创建过程:
1.首先,找到创建对象的那一行代码,点击左侧对应的行数,有了蓝色指向背景即在此处创建了断点(不小心点错了行数或者想取消该断点的话,直接鼠标左键按住蓝色指向标志向外拖动即可)。
2.点击左上角三角运行按钮或者快捷键Command+R运行;代码在断点处停止,点击选中p1,可出现一个小提示框,由于此行代码还未运行,p1的值为空,点击小眼睛图标也可查看p1的各种信息,其中Type
为Person *
,Value
为0(验证了p1是Person类型的指针变量)
3.点击下方控制台的下一步,让程序往下走
4.此时再查看p1的详细信息,发现Value
值为一个十六进制地址,同时可以对比最终控制台打印的p1值的结果,二者相等。
5.点击左侧三角形展开查看更多信息,再点击NSObject左侧的小三角展开,可以看到一个isa
属性,点击小眼睛查看详细信息,发现其Value
值也为一个十六进制地址,其指向类模板的位置;
同时,我们还能看到根据类模板创建的属性,且已被初始化:
_age
属性的类型是基本数据类型,被赋值为0
p1
属性的类型是C语言的指针类型,被赋值为NULL
_name
属性的类型是OC的类指针类型,被赋值为nil
还需注意p1对象中并没有存储方法,而是通过isa
去访问类模板的的方法,主要目的是为了节省空间。
6.继续点击两次下一步,执行完对象属性的赋值,查看对象p1的信息,发现属性已被赋值。最后点击下一步左边的按钮,将程序全部执行完即可
结束啦,别忘了将断点拖动移除喔,不然程序下次依然会在断点处停止~