3

我在我的 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;
}

我正在使用可以在这里找到的 SSKeychain找到的 SSKeychain 。无论内容是否实际存储在钥匙串上,此测试都会消耗大约 75 mb 的内存。

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

4

2 回答 2

2

我在 Leaks Instrument 下运行了您的代码,这就是我从分配跟踪中看到的 -

分配跟踪

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

看看你看到的细节——

细节

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

8,646 个持久对象 - 同样是“现在”分配的对象数量。

瞬态对象 663,288 - 在应用程序生命周期内已在堆上创建的对象总数。您可以从瞬态和持久性之间的区别中看出大多数已发布。

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

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

您还可以从泄漏检查跟踪中看到没有检测到泄漏。

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

现在,我可以想象,在努力增加堆以支持所有这些对象之后,iOS 不会立即将现在释放的堆内存释放回系统;您的应用程序稍后可能再次需要大的堆空间,这就是为什么您的代码报告大量内存正在使用以及为什么您应该警惕尝试构建自己的工具而不是使用可用的工具的原因。

于 2015-10-22T22:11:19.203 回答
1

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

在此处输入图像描述

这篇文章有点过时,但您应该了解基本要点。

Ray Wenderlich - 仪器

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

来自 NSAutoreleasePool 类参考:

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

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

于 2015-10-22T19:42:03.650 回答