我知道当一个对象在堆上实例化时,至少会分配足够的内存来保存对象的ivars。我的问题是编译器如何存储方法。内存中只有一个方法代码实例吗?或者代码是在内存中生成对象的固有部分,与ivars连续存储并执行?
似乎后者就是这种情况,即使像NSString
s这样的平凡对象也需要(相对)大量的内存(NSString
继承NSObject
的方法, )。
或者方法是在内存中存储一次并将指针传递给拥有它的对象?
答案 0 :(得分:8)
在"标准" Objective-C运行时,每个对象在任何其他实例变量之前包含指向它所属的类的指针,就好像基类Object有一个名为的实例变量:
Class isa;
给定类的每个对象共享相同的isa
指针。
该类包含许多元素,包括指向父类的指针,以及方法列表数组。这些方法是专门在这个类上实现的。
struct objc_class {
Class super_class;
...
struct objc_method_list **methodLists;
...
};
这些方法列表都包含一系列方法:
struct objc_method_list {
int method_count;
struct objc_method method_list[];
};
struct objc_method {
SEL method_name;
char *method_types;
IMP method_imp;
};
这里的IMP
类型是一个函数指针。它指向存储方法实现的内存中的(单个)位置,就像任何其他代码一样。
注意:我在这里描述的实际上是ObjC 1.0运行时。当前版本并不像这样存储类和对象;它做了许多复杂,聪明的事情,使方法调用更快。但我所描述的仍然是精神它的工作方式,如果不是它的确切方式。
我还在一些结构中省略了一些区域,这些区域混淆了这种情况(例如,向后兼容性和/或填充)。如果你想看到所有的血腥细节,请阅读真正的标题。
答案 1 :(得分:1)
方法存储在内存中一次。根据平台的不同,可根据需要将它们分页到RAM中。如果您真的想了解更多细节,请阅读Apple的Mach-O和运行指南。除非他们做的事情非常低级,否则程序员通常不再关注自己。
对象并不真正“拥有”方法。我想你可以把它想象成拥有方法的类,所以如果你有400个NSStrings,你仍然只有RAM中每个方法的一个副本。
调用方法时,第一个参数是对象指针self。这就是方法如何知道它需要操作的数据的位置。