iOS開發之 runtime(29) :gdb_objc_realized_classes 淺析

本系列博客是本人的源碼閱讀筆記,如果有 iOS 開發者在看 runtime 的,歡迎大家多多交流。爲了方便討論,本人新建了一個微信羣(iOS技術討論羣),想要加入的,請添加本人微信:zhujinhui207407,【加我前請備註:ios 】,本人博客http://www.kyson.cn 也在不停的更新中,歡迎一起討論


本文完整版詳見筆者小專欄:https://xiaozhuanlan.com/runtime

概述

我們在iOS開發之runtime(27): _read_images 淺析中講解了 class 相關的多個 hash 表:

  • gdb_objc_realized_classes
  • remapped_class_map
  • future_named_class_map
  • nonmeta_class_map

本文我們就詳細的分析一下這幾個 hash map 的第一個: gdb_objc_realized_classes。

gdb_objc_realized_classes
gdb_objc_realized_classes is actually a list of named classes not in the dyld shared cache, whether realized or not.

這段文字出現在文件 objc_runtime_new.mm 中:


這裏翻譯一下:
gdb_objc_realized_classes 是一系列的類列表,這些類不管有沒有實現都不在 dyld 的共享緩存中。
全局搜索 gdb_objc_realized_classes,我們可以看到一系列方法,


這些方法涉及到對於 gdb_objc_realized_classes 的一系列操作,包括:

獲取某個類:

static Class getClass_impl(const char *name)
{
    runtimeLock.assertLocked();
    // allocated in _read_images
    assert(gdb_objc_realized_classes);
    // Try runtime-allocated table
    Class result = (Class)NXMapGet(gdb_objc_realized_classes, name);
    if (result) return result;
    // Try table from dyld shared cache
    return getPreoptimizedClass(name);
}

添加某個類:

/***********************************************************************
* addNamedClass
* Adds name => cls to the named non-meta class map.
* Warns about duplicate class names and keeps the old mapping.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void addNamedClass(Class cls, const char *name, Class replacing = nil)
{
    runtimeLock.assertWriting();
    Class old;
    if ((old = getClass(name))  &&  old != replacing) {
        inform_duplicate(name, old, cls);

        // getNonMetaClass uses name lookups. Classes not found by name 
        // lookup must be in the secondary meta->nonmeta table.
        addNonMetaClass(cls);
    } else {
        NXMapInsert(gdb_objc_realized_classes, name, cls);
    }
    assert(!(cls->data()->flags & RO_META));

    // wrong: constructed classes are already realized when they get here
    // assert(!cls->isRealized());
}

移除某個類:

/***********************************************************************
* removeNamedClass
* Removes cls from the name => cls map.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void removeNamedClass(Class cls, const char *name)
{
    runtimeLock.assertWriting();
    assert(!(cls->data()->flags & RO_META));
    if (cls == NXMapGet(gdb_objc_realized_classes, name)) {
        NXMapRemove(gdb_objc_realized_classes, name);
    } else {
        // cls has a name collision with another class - don't remove the other
        // but do remove cls from the secondary metaclass->class map.
        removeNonMetaClass(cls);
    }
}

而初始化的位置就是我們所知道的 _read_images 方法中:

// namedClasses
// Preoptimized classes don't go in this table.
// 4/3 is NXMapTable's load factor
int namedClassesSize = 
    (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
gdb_objc_realized_classes =
    NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);

add 方法的也位於 _read_images 調用棧中:

- void _objc_init(void)
    - void _dyld_objc_notify_register();
        - void map_2_images();
            - void map_images_nolock();
                - void _read_images();
                    - Class readClass();
                        - void addNamedClass();

需要注意的是:

addNamedClass(cls, mangledName, replacing);

的第二個參數是 mangledName, 也就是上一篇文章筆者 Demo 中給大家從 section 中獲取的數據。
現在看來,gdb_objc_realized_classes 的作用已經很明顯了,即是對所有的類進行緩存:從對應的 section 中讀取所有的類,取出來後以 mangledName 作爲鍵,以 class 結構體作爲值。

至此 gdb_objc_realized_classes 分析結束。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章