iOS基础-OC对象

OC对象

Apple 源码地址:https://opensource.apple.com/tarballs/

ObjectiveC 的本质

ObjectiveC 转为 C/C++
  1. ObjectiveC代码底层实现都是C/C++代码

ObjectiveC -> C/C++ -> 汇编语言 -> 机器语言(0/1)

  1. ObjectiveC面向对象都是基于C/C++的结构体实现的
  2. ObjectiveC 转为 C/C++
  1. 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]
  1. 警告可忽略
    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)

读取指定对象的内存
  1. 断点 - Debug - DeBug WorkFlow - View Memory,输入内存地址
  2. 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);

你可能感兴趣的:(iOS基础-OC对象)