cache_t分析

一、原理

cache_t:结构体,相当于缓存,缓存的是方法, 它要根据自身结构体所容纳的空间大小来决定其所占字节数。(另外,cache_t是结构体,不是结构体指针。Class为结构体指针,所占字节为8)


struct cache_t {

    struct bucket_t *_buckets; // 8
    mask_t _mask;  // 4
    mask_t _occupied; // 4

通过观察bucket_t可以得出缓存的是一些方法

bucket_t结构体.png

cache_t缓存的是一些方法:

struct method_t {
    SEL name;
    const char *types;
    MethodListIMP imp;

通过以下几个步骤可得出新结论:


图片.png
void testInstanceMethod_classToMetaclass(Class pClass){
    
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
    Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));

    Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
    Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
    
    NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
    NSLog(@"%s",__func__);
}

void testClassMethod_classToMetaclass(Class pClass){
    
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getClassMethod(pClass, @selector(sayHello));
    Method method2 = class_getClassMethod(metaClass, @selector(sayHello));

    Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
    Method method4 = class_getClassMethod(metaClass, @selector(sayHappy)); // ?
    
    NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
    NSLog(@"%s",__func__);
}

跟进 class_getClassMethod

Method class_getClassMethod(Class cls, SEL sel)
{
    if (!cls  ||  !sel) return nil;

    return class_getInstanceMethod(cls->getMeta(), sel);
}

继续进 cls->getMeta()

   // NOT identical to this->ISA when this is a metaclass
    Class getMeta() {
        if (isMetaClass()) return (Class)this;
        else return this->ISA();
    }

结论:类方法的底层还是实例方法

二、cache_t分析产生的问题:

通过跑码分析打印_buckets的值,得出cache_t常用来缓存第一次的数据,如果一次输出没有值,则可二次或者多次打印。


图片.png

此时有缓存,而且_buckets还有返回值

三、cache_t的缓存流程

mask_t mask();


图片.png

capacity() 其值为1或0,此时还是不知道缓存哪个方法

探究:到底是缓存在哪个方法

——>capacity()——>


图片.png

此时要继续在当前页探究查找关于capacity()的调用情况——>expand() 由此衍生出了扩容类,看源码走向可以得出oldCapacity和newCapacity,如果oldCapacity没有,则*2扩容两倍作为新的INIT_CACHE_SIZE


图片.png

继续跟进INIT_CACHE_SIZE,此时看源码1左移两位100=>4,结果应该为4,但是此时的打印结果_occupied的值还是1,而_mask的值却是3,这是为什么呢?
图片.png

探究:从何时进行扩容

图片.png

跟进void cache_t::expand()中的INIT_CACHE_SIZE

enum {
    INIT_CACHE_SIZE_LOG2 = 2,
    INIT_CACHE_SIZE      = (1 << INIT_CACHE_SIZE_LOG2)
};

继续在当前页查找expand(),直到找到cache_fill_nolock会发现,此时的expand()是在591行的时候被调用的(调起了方法扩容)


图片.png

源码流程分析:
570行:cache_fill_nolock:从缓存入口进入
579行:cache_getImp:再从缓存中得到Imp,判断是否有缓存,缓存中如果拿到,则直接返回
581:cache_t *cache = getCache(cls) :如果没有拿到,要从getCache获取原来的结构体cls
582:cache_key_t key = getKey(sel) :如果没有拿到,要从 getKey获取sel

cache_key_t getKey(SEL sel) 
{
    assert(sel);
    return (cache_key_t)sel;
}

585:occupied():读取开辟占用

587:if (cache->isConstantEmptyCache()):
继续分析三大中情况:
1.cache->reallocate
2.bucket_t bucket = cache->find(key, receiver);
3.bucket->set(key, imp);
591:else if (newOccupied <= capacity / 4 * 3) :正常添加bucket
594:cache->expand():如果以上两种都不是,则
扩容*

图片.png

1.oldCapacity*2 :扩容2倍
2.reallocate(oldCapacity, newCapacity);
3.cache_collect(false); 清理内存


图片.png

整体处理流程大致如下图所示:


图片.png
图片.png

自我感觉有点糙,还可以再细化,后面有机会,我会给大家添加上一个关于缓存的流程分析图会更加直观和清晰~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 我们这节课探索cache_t,首先我们提出问题,带着问题去找答案。 1.cache_t是什么? 从源码上可以看出c...
    瞬间完善阅读 290评论 0 1
  • 我们在上个章节类的结构分析中大概描述了一下类的属性,成员变量,实例方法,类方法的存储位置。接下来我们去分析类的结构...
    Easting阅读 318评论 0 3
  • 在iOS中对象或者类调用一个方法,这个方法是会被缓存起来的,当下一次再次调用这个方法的时候,会先从缓存里查找,如果...
    Joker_King阅读 751评论 0 2
  • Runtime系列文章 Runtime原理探究(一)—— isa的深入体会(苹果对isa的优化)Runtime原...
    RUNNING_NIUER阅读 1,834评论 2 11
  • 1. cache的结构 我们之前探索过Class的结构以及其内部的成员,其中了解到了isa,superClass以...
    尘舒阅读 3,046评论 6 22