为什么这个循环流失内存?

时间:2015-10-22 19:05:39

标签: ios memory memory-management memory-leaks sskeychain

我正在为我的iOS项目使用ARC,并使用名为SSKeychain的库来访问/保存项目到钥匙串。我希望我的应用程序每10秒左右访问一次钥匙串项目(以访问API安全令牌),因此我想测试这个库以查看它经常调用时的处理方式。我做了这个循环来模拟一个疯狂的调用量,并注意到它在iPhone(而不是模拟器)上运行时会流出大量(~75 mb)的内存:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSUInteger beginMemory = available_memory();
        for (int i = 0; i < 10000; ++i) {

            @autoreleasepool{
                NSError *  error2 = nil;
                SSKeychainQuery*  query2 = [[SSKeychainQuery alloc] init];
                query2.service = @"Eko";
                query2.account = @"loginPINForAccountID-2";
                query2.password = nil;
                [query2 fetch:&error2];
            }
        }
        NSUInteger endMemory = available_memory();

        NSLog(@"Started with %u, ended with %u, used %u", beginMemory, endMemory, endMemory-beginMemory);
    });

    return YES;
}

static NSUInteger available_memory(void) {
    // Requires #import <mach/mach.h>
    NSUInteger result = 0;
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size) == KERN_SUCCESS) {
        result = info.resident_size;
    }
    return result;
}

我正在使用可以找到的here SSKeychain。无论事情是否实际存储在钥匙串中,该测试都会流出约75 MB的内存。

任何想法发生了什么?我的测试方法有缺陷吗?

2 个答案:

答案 0 :(得分:2)

我在Leaks Instrument下运行你的代码,这是我在Allocations轨道上看到的 -

Allocations Track

您期望的是 - 在循环期间分配了大量内存然后将其释放。

看看你看到的细节 -

Detail

堆上的持久字节为2.36MB - 这是应用程序“现在”实际使用的内存(即在应用程序“空闲”循环之后)

8,646的持久对象 - 再次,“现在”分配的对象数。

瞬态对象663,288 - 在应用程序生命周期内在堆上创建的对象总数。你可以从瞬态和持久性的差异中看出大多数已被释放。

总字节数为58.70MB - 这是执行期间分配的内存总量。不是正在使用的内存总量,而是已分配的总量,无论这些分配是否随后被释放。

浅粉色和深粉色条之间的差异还显示了当前“活动”内存使用与总使用量之间的差异。

您还可以从“泄漏检查”轨迹中看到没有检测到泄漏。

因此,总而言之,您的代码会使用大量的瞬态内存,就像您对紧密循环所期望的那样,但是在应用程序执行的正常过程中,您不会看到此内存使用,其中密钥链被访问了几次每秒或每分钟或其他什么。

现在,我想,在努力扩展堆以支持所有这些对象的过程中,iOS不会发布现在将堆内存直接释放回系统的问题。您的应用程序有可能在以后再次需要大堆空间,这就是为什么您的代码报告正在使用大量内存以及为什么您应该小心尝试构建自己的检测而不是使用可用的工具。 / p>

答案 1 :(得分:1)

您应该使用仪器来确定导致泄漏的位置/原因。它是一个非常好的工具,知道如何使用。

enter image description here

这篇文章有点过时,但你应该得到基本的要点。

Ray Wenderlich - Instruments

离开 Paulw11的评论我偶然发现了这个,

From NSAutoreleasePool Class Reference:

  

Application Kit在主线程上创建一个自动释放池   事件循环的每个循环的开始,并将其排出   结束,从而释放任何生成的自动释放对象   处理事件。

因此,当您使用仪器进行检查时,请确保事件循环有时间完成。也许您需要做的就是让程序继续运行,然后暂停调试器并再次检查仪器。