zoukankan      html  css  js  c++  java
  • NSCache缓存怎么来的

    什么是NSCache

    NSCache主要用来存储临时数据(键值对),当内存资源不够时,系统会自动释放部分数据。它有三个特点:
    • NSCache为了保持不占用过多的系统内存,它有多种自动回收内存策略;当系统内存出现不足时,它会回收部分内存使系统正常运转,这种回收是不可控的。
    • 可以在多线程中对NSCache进行访问,同时不需要加锁,因为它是线程安全的。
    • 与NSMutableDictionary不同,NSCache不会copy其内部的键对象。

    由上边的特点看出,NSCache是一个很好的内存缓存类,通过它我们可以实现数据的缓存功能。常见的开源框架中也有NSCache的使用,AFN的图片缓存,SDWebImage等。


    NSCache测试

    下面验证NSCache的特性,包含三个部分。NSCache的缓存能力有多大?多线程访问下是否安全?是否会copy其内部对象?

    1. 缓存能力
    NSCache提供了totalCostLimit和countLimit属性让外界能够对其进行缓存大小和缓存数量进行限制,但是不精确。网上其他的帖子说到大约NSCache的缓存能力是500M,现在我们对其验证。

        NSCache *cache = [[NSCache alloc] init];
        
        int a = 0;
        while (YES) {
            NSString *string = @"一长串字符串"; // 大约1000个左右字符
            NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
            NSString *key = [NSString stringWithFormat:@"%d", a];
            [cache setObject:data forKey:key];
            a++;
        }

    通过上述的代码运行在iPhone6上,内存升到600M多点直接崩溃,那么极限是500多应该是正确的。同时在快速达到内存极限时,系统是来不及释放回收的,使用时应当注意,而且上边的代码是死循环,速度非常快。

    2. 多线程访问

    多线程访问单独读取是不会造成问题的,除非访问线程数过多,这里我们模拟多线程同时写入的情况。

        NSCache *cache = [[NSCache alloc] init];
        NSString *string = @"一长串字符串"; // 大约1000个左右字符
        for (int i = 0; i < 10; i++) {
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                [cache setObject:[NSString stringWithFormat:@"%d%@",i,string] forKey:@"MulPth"];
                NSLog(@"object is %@", [cache objectForKey:@"MulPth"]);
            });
        }

    string若设置为特别短的字符串,效果可能不是很明显,所以将缓存能力中的字符串拷贝过来测试,从打印结果看,时间戳有明显差异,同时顺序也不是0123456789,而其余的内容一致,可以得出是线程安全的。
    本质上,NSCache在其内部使用了pthread_mutex互斥锁进行线程安全保护。

    3.Copy协议

    仔细观察NSCache的setObject:forKey方法,发现它的key是没有遵循NSCopying协议的。

    系统方法:
    - (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost
    - (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;

    而NSMutableDictionary的key遵循了NSCopying协议:
    - (void)setObject:(ObjectType)anObject forKey:(KeyType <NSCopying>)aKey;

    通过方法的参数我们已经可以看出NSCache和NSMutableDictionary的区别,下面用代码测试下。
    新建两个类Person作为object,Man(实现NSCopying)作为Key,同时给它们定义一个Name属性,方便测试(看内存地址也行,个人习惯添加属性)。

        Man *m = [[Man alloc] init];
        m.Name = @"MMM";
        
        Person *p1 = [[Person alloc] init];
        p1.Name = @"小明";
        Person *p2 = [[Person alloc] init];
        p2.Name = @"小东";
        Person *p3 = [[Person alloc] init];
        p3.Name = @"小西";
        
        NSCache *cache = [[NSCache alloc] init];
        [cache setObject:@[p1,p2,p3] forKey:m];
        [cache setObject:@[p1,p2] forKey:m];
        
        NSMutableDictionary *mdic = [NSMutableDictionary dictionaryWithCapacity:0];
        [mdic setObject:@[p1,p2,p3] forKey:m];
        [mdic setObject:@[p1,p2] forKey:m];

    打印结果:

        

    打印结果中看出NSCache没有copy,NSMutableDictionary进行了copy。在开发中,NSCache,NSMapTable和NSMutableDictionary很像,都是键值存储,使用时要注意它们的区别和特性。

  • 相关阅读:
    这些天对iframe的初步运用
    后台制作与商品装入
    主页的设计
    DevOps
    Nginx
    DevOps
    DevOps
    Cluster
    Cluster
    Cluster
  • 原文地址:https://www.cnblogs.com/xuanyishare/p/11105359.html
Copyright © 2011-2022 走看看