目录
一 OC 中的内存分配
student 结构体明明是20?为什么是24个字节,因为结构体会按照本身成员变量最大的内存进行对齐,最大成员变量是8个字节,因此就是8的倍数,24个字节。
class_getInstanceSize 返回的是该类内存对齐之后的成员变量的内存空间,你需要多少,计算多少。
malloc_size 是实际系统分配的内存空间
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <malloc/malloc.h>
// 模拟 NSObject 的实现
struct NSObject_IMPL
{
Class isa;
};
// 模拟Student 的实现
struct Student_IMPL
{
struct NSObject_IMPL IVARS;// 8
int _no;// 4
int _age;// 4
int _height;// 4
}; // 以上实际是20个字节,由于必须是8的倍数,所以是24个字节
@interface Student:NSObject
{
@public
int _no;
int _age;
int _height;
}
@end
@implementation Student
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Student *stu1 = [[Student alloc]init];
// 24
NSLog(@"%zd",sizeof(struct Student_IMPL));
// 24 - 32
NSLog(@"%zd -- %zd",class_getInstanceSize([Student class]),malloc_size((__bridge const void *)(stu1)));
}
return 0;
}
虽然结构体只需要24个字节,可以看出来student 实例对象占用的字节是32个字节
前面也有讲到 allozWithZone 方法调用中
inline size_t instanceSize(size_t extraBytes) const {
if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
return cache.fastInstanceSize(extraBytes);
}
// extraBytes 一般是传递的是0
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
{
void *bytes;
size_t size;
// Can't create something for nothing
if (!cls) return nil;
// Allocate and initialize
size = cls->alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
if (zone) {
bytes = malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {
// 这个位置传递的就是24,但是实际分配的内存确实32,所以还是要看calloc 底层的实现
bytes = calloc(1, size);
}
return objc_constructInstance(cls, bytes);
}
calloc 的源码实现,去苹果源码开源下载 找到malloc 的源码包文件
、https://opensource.apple.com/tarballs/libmalloc/
在 malloc.c 文件中找到的calloc 函数的实现
void *
calloc(size_t num_items, size_t size)
{
void *retval;
retval = malloc_zone_calloc(default_zone, num_items, size);
if (retval == NULL) {
errno = ENOMEM;
}
return retval;
}
void *
malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size)
{
void *ptr;
size_t alloc_size;
if (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {
internal_check();
}
if (os_mul_overflow(num_items, size, &alloc_size) || alloc_size > MALLOC_ABSOLUTE_MAX_SIZE){
errno = ENOMEM;
return NULL;
}
ptr = zone->calloc(zone, num_items, size);
if (malloc_logger) {
malloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE | MALLOC_LOG_TYPE_CLEARED, (uintptr_t)zone,
(uintptr_t)(num_items * size), 0, (uintptr_t)ptr, 0);
}
return ptr;
}
以上说了那么多,这这个源码中有一个 NANO_MAX_SIZE 这个宏定义,堆上分配内存的时候,系统把一块块内存都划分好的
即使你不够16个字节,也给你分配16个字节,这里都是16的倍数。
#define NANO_MAX_SIZE 256 /* Buckets sized {16, 32, 48, 64, 80, 96, 112, ...} */
所以以上结构体只需要24个字节,但是系统就是分配给你32个字节的内存