OC对象
Apple 源码地址:https://opensource.apple.com/tarballs/
ObjectiveC 的本质
ObjectiveC 转为 C/C++
- ObjectiveC代码底层实现都是C/C++代码
ObjectiveC -> C/C++ -> 汇编语言 -> 机器语言(0/1)
- ObjectiveC面向对象都是基于C/C++的结构体实现的
- ObjectiveC 转为 C/C++
- cd 到将要转化的文件的文件夹
- clang -rewrite-objc main.m -o main.cpp (全平台)
- xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp [sdk:os平台 arch:架构(模拟器-i836/32bit-armv7/64bit-arm64]
- 警告可忽略
clang:XCode内置的LLvm编译器前段
@interface NSObject {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
// 指针 占8个字节 32bit占4个字节
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
@end
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
struct NSObject_IMPL {
Class isa;
};
// objc_object 与 NSObject_IMPL 的关系?
NSObject对象占多少内存
/**
[NSObject class] 类实例对象的成员变量所占用的大小 isa指针占用8byte
根据对象的属性类型和个数增加
*/
class_getInstanceSize([NSObject class]);
/**
获取objc指向的内存地址大小 16byte
根据对象的属性类型和个数增加
*/
malloc_size((__bridge const void *)objc);
// 源码:objc -> alloc 方法 -> allocWithZone 方法
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;
}
// 注意: OBJC_ISA_AVAILABILITY 为 attribute((deprecated))过期标记
系统分配了16Byte给NSObject对象(malloc_size)
64bit环境下只使用了8Byte的空间(class_getInstanceSize)
读取指定对象的内存
- 断点 - Debug - DeBug WorkFlow - View Memory,输入内存地址
- LLVM 指令 读取内存
- p objc (输出对象内存地址)
- memory read [内存地址] 或 x [内存地址] (读取内存)
- memory read/数量格式字节数 或 x/数量格式字节数 (读取指定内存)
格式:x是十六进制,f是浮点,d是十进制
字节数:b(byte)是1Byte,h(half word)是2字节,w(word)是4字节,g(giant word)是8字节
(lldb) p objc
(NSObject *) $0 = 0x000000010200d800
(lldb) memory read 0x000000010200d800
0x10200d800: 41 71 67 93 ff ff 1d 00 00 00 00 00 00 00 00 00 Aqg.............
0x10200d810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
(lldb) x 0x000000010200d800
0x10200d800: 41 71 67 93 ff ff 1d 00 00 00 00 00 00 00 00 00 Aqg.............
0x10200d810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
(lldb) x/4xw
0x10200d820: 0x00718c90 0x00000001 0x00711e01 0x00000001
(lldb) memory read/4xw
0x10200d830: 0x00000021 0x00000000 0x0000001c 0x00000000
写内存
- memory write [内存地址] [替换值]
(lldb) x 0x000000010200d800
0x10200d800: 41 71 67 93 ff ff 1d 00 00 00 00 00 00 00 00 00 Aqg.............
0x10200d810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
(lldb) memory write 0x10200d807 9
(lldb) x 0x000000010200d800
0x10200d800: 41 71 67 93 ff ff 1d 09 00 00 00 00 00 00 00 00 Aqg.............
0x10200d810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
一个十六进制位 代表 4个二进制位,两个十六进制位,一个字节
内存对齐:结构体的最终内存大小必须是最大成员大小的倍数。
内存分配注意
问题:实际分配的内存大于属性加起来需要的内存
@interface AXObject : NSObject
{
@public
NSString *_name;
int _age;
}
@end
// 输出
AXObject *axObjc = [[AXObject alloc] init];
NSLog(@"class_getInstanceSize %zd", class_getInstanceSize([AXObject class])); // 24
NSLog(@"malloc_size %zd", malloc_size((__bridge const void *)axObjc)); // 32
NSLog(@"sizeof %zd",sizeof(struct AXObject_IMPL)); // 24
原因:操作系统真正分配内存也要遵守内存对齐。
源码:libmalloc search calloc 方法
#define NANO_MAX_SIZE 256 /* Buckets sized {16, 32, 48, 64, 80, 96, 112, ...} */
操作系统中有buckets,buckets 的内存大小是16的倍数,最大为256字节。
结论:iOS 堆空间里,创建对象分配的内存都是16的倍数。
- sizeof 返回计算结构体的内存大小
- class_getInstanceSize 返回实例对象所有成员变量所需要的内存大小
- malloc_size 返回系统实际分配的内存大小
以上皆返回内存对齐过的内存大小。
malloc 源码
GNU - GNU's Not Unix! (开源组织)
https://www.gnu.org/
软件 -> search libc -> sources -> via ftp -> 下载最新版本
源码:malloc-alignment.h search MALLOC_ALIGNMENT 内存对齐参数
// i386
#define MALLOC_ALIGNMENT 16
// generic
// iOS 中 SIZE_SZ == 8
// iOS 中 long double == 16
#define MALLOC_ALIGNMENT (2 * SIZE_SZ < __alignof__ (long double) \
? __alignof__ (long double) : 2 * SIZE_SZ)
sizeof 注意点
sizeof 运算符 -> 编译时确认类型
NSObject *p = [[NSObject alloc] init];
NSLog(@"sizeof %zd", sizeof(p));
// 实际上,运行时,代码为: NSLog(@"sizeof %zd", 8);