美文网首页
YYCache 源码流程

YYCache 源码流程

作者: 双手插兜Jeff | 来源:发表于2020-01-01 08:26 被阅读0次

    存储技术

    • 基于文件读写
    • 基于 mmap 文件内存映射
    • 基于数据库

    基于文件系统

    SDWebImage 等缓存:一个 Value 对应一个文件。
    不方便扩展、没有元数据、难以实现较好的淘汰算法、数据统计缓慢。

    Memory Map-mmap

    缺点:
    热数据的文件不要超过物理内存大小,不然 mmap 会导致内存交换严重降低性能。
    内存中的数据是定时 flush 到文件的,如果数据还未同步时程序挂掉,就会导致数据错误。

    优点:

    普通读取文件。

    disk -> 缓存 -> 内存中

    普通写文件

    内存操作 -> 缓存 ->disk

    mmap 内存操作 -> disk

    mmap

    比如文件大小为50k。会在内存中申请>50 具体是4k的整数倍。所以此处可以是52k的内存。

    然后你就在0-50k的区域内进行读写,过一段时间,会把内存中的数据同步到disk中。

    因为是相当于对内存的读写,所以读写速度很快。

    Link

    认真分析mmap:是什么 为什么 怎么用

    从内核文件系统看文件读写过程

    数据库

    SQLite

    • 写入:数据库大于直接写入文件。
    • 读取:
      • 大于20k,文件读取更快。
      • 小于20k,数据库的读取快

    锁的使用

    OSSpinLock,自旋锁,适合内存缓存的存取
    dispatch_semaphore,等待时不会消耗 CPU 资源,适合磁盘缓存


    Link

    源码分析

    YYMemoryCache

    _YYLinkedMapNode

    _YYLinkedMapNode *_prev; 
    _YYLinkedMapNode *_next; 
    id _key;
    id _value;
    NSUInteger _cost; // The cost with which to associate the key-value pair.
    NSTimeInterval _time; // 插入的时间,到时候可以依据这个清除超时对象
    

    双向链表中的一个节点。

    _YYLinkedMap

    CFMutableDictionaryRef _dic; // do not set object directly
    NSUInteger _totalCost;
    NSUInteger _totalCount;
    _YYLinkedMapNode *_head; // MRU, do not change it directly
    _YYLinkedMapNode *_tail; // LRU, do not change it directly
    

    手动维持一个支持LRU (least-recently-used)的哈希表。

    YYMemoryCache

       pthread_mutex_t _lock; 
        _YYLinkedMap *_lru;
        dispatch_queue_t _queue; // 用于释放对象
    

    特点:

    • 访问key,也会计算在LRU里面

    • 添加key-value,先添加node,再修剪cost,count

    • 进入background,内存警告。你都可以自定义操作。

    • 修剪:每5s做一次裁剪。 清除超过限定的对象。

      • 依据:cost,count,age(子线程中完成)
    • Nothing

    总结:

    YYMemoryCache是一个包装了字典的,双向链表的对象。

    支持LRU。

    依据cost, count , age来裁剪超载对象。(因为LRU的关系,都从尾部开始裁)

    支持内存警告,进入后台时的自定义操作。

    YYKVStorage

    数据库名词解释:

    blob // (binary large object) 二进制大对象。可以是一张图片或一个声音文件。

    File:
     /path/
          /manifest.sqlite
          /manifest.sqlite-shm
          /manifest.sqlite-wal
          /data/
               /e10adc3949ba59abbe56e057f20f883e
               /e10adc3949ba59abbe56e057f20f883e
          /trash/
                /unused_file_or_folder
    
     SQL:
     create table if not exists manifest (
        key                 text, // 传值获取
        filename            text, // 传值获取
        size                integer, // 计算文件获取
        inline_data         blob, // 如果文件名length=0,此处插入文件。
        奇怪的设定。相当于把本来存在数据库外的文件,存在了数据库里面。
        
        modification_time   integer, // 最后修改时间
        last_access_time    integer,    // 最后访问时间
        extended_data       blob, // 传值获取
        primary key(key)
     ); 
     create index if not exists last_access_time_idx on manifest(last_access_time);
    
    image.png

    YYDiskCache

    YYKVStorage *_kv;
    dispatch_semaphore_t _lock;
    dispatch_queue_t _queue;            // 并发queue
    _freeDiskSpaceLimit         // 占用空间极限 0就是没有限制
    _countLimit | _costLimit | _ageLimit
    TrimInterval = 60                   // 修剪上面limit的intv
    
    image.png

    YYCache

    存储

    • 先存内存

      • YYMemoryCache 进行存储
    • 再存disk

      • YYDiskCache save kv

        • 序列化对象
        • 依据value大小(默认20k),选择存储方式
        • YYKVStorage save kv

    获取

    • 从YYMemoryCache中获取

    • 如果内存没有,从本地获取。

      • 从kv获取
      • 反序列化(可能需要拼装上extData)
      • 返回对象(同时缓存到YYMemoryCache,方便下次获取)

    细节

    setObject的 obj 都遵循NSCoding协议

    修剪:Disk定期修剪是60s,Memory是5s。

    疑惑

    mmap 热数据的文件不要超过物理内存大小,不然 mmap 会导致内存交换严重降低性能啥意思?

    相关文章

      网友评论

          本文标题:YYCache 源码流程

          本文链接:https://www.haomeiwen.com/subject/mdswoctx.html