iOS Baguwen (1) Essence Exploration d'objets (Partie 1)

la nature de l'objet

La couche inférieure du code Objective-C est implémentée par C/C++, donc l'Objective-C orienté objet est implémenté sur la base de la structure de données C/C++.  La figure suivante montre plusieurs processus de conversion du langage OC en langage machine

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

Le premier processus peut être effectué par le compilateur clong. Réécrivez le code OC en code C++.

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

Vous pouvez également spécifier la plate-forme, spécifier le mode d'architecture spécifié et la quantité de code est inférieure, ce qui est pratique pour la recherche.

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

image.png

Code CO

@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;
}

复制代码

Code C++ (beaucoup de suppressions, facile à lire)

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 conclusion:

L'essence de l'objet OC est en fait une structure, et les informations de variable membre de l'objet sont stockées dans l'objet.

processus de création d'objet

Nous savons que l'initialisation d'un objet utilise en fait les callocfonctions du langage c. Mais en fait, avant cette opération, il faut aussi connaître la taille mémoire requise par l'objet. Vous pouvez donc le voir dans le code source objc4 (l'implémentation de la méthode dans objc4-818.2/runtime/objc-runtime-new.mm _class_createInstanceFromZone)

image.pngVoici le code clé pour la création d'objet. On peut grosso modo le résumer en 3 parties.

1. Calculer la taille de la mémoire de l'objet (cls->instanceSize)
2. Demander de l'espace mémoire au système (calloc)
3. Définir le pointeur isa, l'associer à l'objet de classe et initialiser les informations de l'objet (obj->initInstanceIsa )

la taille de l'objet

Il existe 3 API sur la taille des objets dans OC.

API posséder une bibliothèque sens
taille de fondation espace variable membre
class_getInstanceSize Durée est l'espace occupé par toutes les variables membres
malloc_size malloc est l'espace alloué par l'objet

sizeofLa class_getInstanceSizedifférence entre et est que, sizeofpour un symbole, la valeur est déterminée pendant le processus de compilation, tandis que class_getInstanceSizepour une fonction, le résultat n'est connu que pendant le processus en cours d'exécution.

Code ci-dessus :

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));
}
复制代码

résultat de l'opération :

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的结果必须是其内部最大成员的整数倍,不足的要补齐。

对象内存对齐

L'alignement de la mémoire de l'objet oc peut être compris approximativement comme la mémoire requise doit être un multiple de 16. Ceci est géré par le système d'allocation de mémoire d'Apple. Afin d'optimiser davantage l'efficacité de lecture de la mémoire, il existe un concept de seau lorsque la mémoire est utilisée. Apple divisera la mémoire en plusieurs compartiments, et la plus petite unité du compartiment est de 16 octets. Cela peut être confirmé dans le code source de libmalloc .

image.pngEnfin, vous pouvez vous référer au code source de l'alignement de mémoire similaire d'Apple dans le code source et utiliser l'opération de déplacement.

#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;
}
复制代码

Guess you like

Origin juejin.im/post/7088621847465590791