@interface LDPerson : NSObject
{
int _no;
int _age;
}
@end
LDPerson底层实现:
struct NSObject_IMPL{
Class isa;
}
struct LDPerson_IMPL
{
struct NSObject_IMPL NSObject_IVARS;//8字节
int _no;//4字节
int _age;//4字节
}
所以上图中LDPerson
的instance
对象占用16字节的内存.
思考下图中LDPerson
的instance
对象占用的内存大小
@interface LDPerson : NSObject
{
int _age;
int _height;
int _no;
}
底层实现:
struct NSObject_IMPL{
Class isa;
}
struct LDPerson_IMPL
{
struct NSObject_IMPL NSObject_IVARS;//8字节
int _no;//4字节
int _height;//4字节
int _age;//4字节
}
推断:实际占用20字节,因为内存对其原则,必须为最大成员变量 所占内存的整数倍.所以该instance对象应该占用24个字节.
通过代码验证:
image.png通过代码我们可以发现:之前的推论是错误的.
LDPerson
的instance
对象实际占用24字节,分配时占用32字节.
通过内存图分析:
image.png如图红框部分一般为连续内存地址,即为
LDPerson
的instance对象.可以看出占用32个字节.
通过OC代码转成C/C++代码再次查看
1. cd 目标路径
2.xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
查看后得知LDPerson底层实现结构就如我们上面所写,所以LDPerson确实占用24字节,分配32字节.
查看objc4
开源代码
- 检索
allocWithZone
查看.mm文件
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
{
id obj;
#if __OBJC2__
// allocWithZone under __OBJC2__ ignores the zone parameter
(void)zone;
obj = class_createInstance(cls, 0);
#else
if (!zone) {
obj = class_createInstance(cls, 0);
}
else {
obj = class_createInstanceFromZone(cls, 0, zone);
}
#endif
if (slowpath(!obj)) obj = callBadAllocHandler(cls);
return obj;
}
主要代码为:
image.png
id
class_createInstance(Class cls, size_t extraBytes)
{
return _class_createInstanceFromZone(cls, extraBytes, nil);
}
可以看到extraBytes
传入的值为0.再看_class_createInstanceFromZone
的实现:
id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil)
{
if (!cls) return nil;
assert(cls->isRealized());
// Read class's info bits all at once for performance
bool hasCxxCtor = cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
bool fast = cls->canAllocNonpointer();
size_t size = cls->instanceSize(extraBytes);
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (!zone && fast) {
obj = (id)calloc(1, size);
if (!obj) return nil;
obj->initInstanceIsa(cls, hasCxxDtor);
}
else {
if (zone) {
obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
} else {
obj = (id)calloc(1, size);
}
if (!obj) return nil;
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
}
if (cxxConstruct && hasCxxCtor) {
obj = _objc_constructOrFree(obj, cls);
}
return obj;
}
image.png
所以我们可以看到,实际分配内存大小就在
instanceSize
和calloc
两个函数
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()->ro->instanceSize;
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
对比size_t instanceSize(size_t extraBytes)
和class_getInstanceSize(Class cls)
的实现
size_t class_getInstanceSize(Class cls)
{
if (!cls) return 0;
return cls->alignedInstanceSize();
}
因为extraBytes
为0所以两个函数的返回值类似,只是前者多了一个与16字节的判断.
然后我们再看obj = (id)calloc(1, size);
这个函数,如下可知C语言的标准库,看不到实现的代码.
通过其他开源代码查看calloc
函数的实现
- 打开开源代码
- 检索
libmalloc
关键字
3.libmalloc-140.40.1.tar.gz
4.按如下所示查找到calloc
实现如下:
iOS堆内存 分配原则:都是16的倍数
可通过下面的方式查看:
class_getInstanceSize():
创建一个实例对象,至少需要多少内存
对齐后
.malloc_size()
创建一个实例对象,实际上分配多少内存.
网友评论