iOS Baguwen (1) Esencia Exploración de objetos (Parte 1)

la naturaleza del objeto

La capa inferior del código de Objective-C se implementa mediante C/C++, por lo que la orientación a objetos de Objective-C se implementa en función de la estructura de datos de C/C++.  La siguiente figura muestra varios procesos de conversión de lenguaje OC a lenguaje máquina.

9735490aae7a4eb68f2fc2945a3ee13e~tplv-k3u1fbpfcp-zoom-in-crop-mark-1304-0-0-0.image.png

El primer proceso puede ser realizado por el compilador de clonación. Reescriba el código OC en código C++.

clang -rewrite-objc <oc fileName> -o <c++ fileName>
复制代码

También puede especificar la plataforma, especificar el modo de arquitectura especificado y la cantidad de código es menor, lo que es conveniente para la investigación.

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc < OC FileName> -o <Cpp FileName>
复制代码

imagen.png

código OC

@interface OSTestObject1 : OSTestObject
{
    @public int _count2;
}
@end

@interface OSTestObject : NSObject
- (void)print;
@end

int object_c_source_m() {
    OSTestObject1 *obj1 = [[OSTestObject1 alloc] init];
    return 0;
}

复制代码

Código C++ (muchas eliminaciones, fácil de leer)

struct NSObject_IMPL {
    Class isa;
};

struct OSTestObject_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
};

struct OSTestObject1_IMPL {
    struct OSTestObject_IMPL OSTestObject_IVARS;
    int _count2;
};

int object_c_source_m() {
    OSTestObject1 *obj1 = ((OSTestObject1 *(*)(id, SEL))(void *)objc_msgSend)((id)((OSTestObject1 *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("OSTestObject1"), sel_registerName("alloc")), sel_registerName("init"));
    return 0;
}

复制代码

En conclusión:

La esencia del objeto OC es en realidad una estructura, y la información de la variable miembro del objeto se almacena en el objeto.

proceso de creación de objetos

Sabemos que el inicio de un objeto en realidad usa las callocfunciones en el lenguaje c. Pero, de hecho, antes de esta operación, también necesita saber el tamaño de memoria requerido por el objeto. Entonces puede verlo en el código fuente de objc4 (la implementación del método en objc4-818.2/runtime/objc-runtime-new.mm _class_createInstanceFromZone)

imagen.pngAquí está el código clave para la creación de objetos. A grandes rasgos podemos resumirlo en 3 partes.

1. Calcule el tamaño de memoria del objeto (cls->instanceSize)
2. Solicite espacio de memoria del sistema (calloc)
3. Establezca el puntero isa, asócielo con el objeto de clase e inicialice la información del objeto (obj->initInstanceIsa )

el tamaño del objeto

Hay 3 API sobre el tamaño del objeto en OC.

API biblioteca propietaria significado
tamaño de Fundación espacio de variables miembro
class_getInstanceSize tiempo de ejecución es el espacio ocupado por todas las variables miembro
malloc_tamaño malloc es el espacio asignado por el objeto

sizeofLa class_getInstanceSizediferencia entre y es que, sizeofpara un símbolo, el valor se determina durante el proceso de compilación, mientras que class_getInstanceSizepara una función, el resultado solo se conoce durante el proceso de ejecución.

Código anterior:

struct objcet_test {
    Class isa;
};

- (void)test1 {
    NSLog(@"结构体所占内存为%zd",sizeof(struct objcet_test));
    NSObject *objc1 = [[NSObject alloc] init];
    NSLog(@"nsobject 的成员变量所占空间为%zd",class_getInstanceSize([NSObject class]));
    NSLog(@"objc1所占内存空间为%zd",malloc_size((__bridge const void *)objc1));
}
复制代码

resultado de la operación:

2022-04-18 14:41:00.898227+0800 ObjectStudy[9601:189987] 结构体所占内存为8 2022-04-18 14:41:00.746690+0800 ObjectStudy[9394:185408] nsobject 的成员变量所占空间为8

2022-04-18 14:41:00.746737+0800 ObjectStudy[9394:185408] objc1所占内存空间为16

内存对齐

造成上面情况的根本原因是内存对齐。可以大致理解为这样存储虽然数据空间会增大,但访问数据的效率会更高,是一种牺牲空间换取时间的操作。

在OC中是经过了2次内存对齐,一种是结构体的内存对齐,一种是对象的内存对齐。

其中class_getInstanceSize获取到的是结构体内存对齐后的结果。 而malloc_size获取到的是对象内存对齐后的结果。

结构体内存对齐规则

  1. 数据成员对齐规则:结构(struct)的第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存储)。 

  2. 结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储)。

  3. 收尾工作:结构体的总大小,也就是sizeof的结果必须是其内部最大成员的整数倍,不足的要补齐。

对象内存对齐

La alineación de la memoria de objetos oc se puede entender aproximadamente como la memoria requerida debe ser un múltiplo de 16. Esto es manejado por el sistema de asignación de memoria de Apple. Para optimizar aún más la eficiencia de lectura de la memoria, existe un concepto de depósito cuando se utiliza la memoria. Apple dividirá la memoria en varios cubos, y la unidad más pequeña del cubo es de 16 bytes. Esto se puede confirmar en el código fuente de libmalloc .

imagen.pngFinalmente, puede consultar el código fuente de la alineación de memoria similar de Apple en el código fuente y usar la operación de desplazamiento.

#define SHIFT_NANO_QUANTUM 4
#define NANO_REGIME_QUANTA_SIZE (1 << SHIFT_NANO_QUANTUM)

static MALLOC_INLINE size_t
segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey)
{
    size_t k, slot_bytes;
    if (0 == size) {
        size = NANO_REGIME_QUANTA_SIZE; // Historical behavior
    }
        k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; // round up and shift for number of quanta
        slot_bytes = k << SHIFT_NANO_QUANTUM; // multiply by power of two quanta size
    *pKey = k - 1; // Zero-based!
    return slot_bytes;
}
复制代码

Supongo que te gusta

Origin juejin.im/post/7088621847465590791
Recomendado
Clasificación