AWS SNS Unsubscribe循环不释放内存 - 导致Jetsam杀死应用程序

时间:2015-03-24 01:25:05

标签: ios amazon-web-services amazon-sns

问题

当我取消订阅我的端点订阅时,乐器内存图从32MB变为300MB,应用程序被Jetsam杀死。我的理解是AWS BFTasks自己清理......如果我删除do...while并允许它处理前100个订阅,那么一切正常。

过程

我的开发应用程序中有大约8000个订阅,它使用AWS SNS将警报推送到iOS设备和电子邮件。在用户选择他们想要的订阅后,我删除他们现有的订阅,然后订阅他们的新订阅。 [_awsSnsClient listSubscriptions:request]最多返回100个订阅,我循环浏览这些订阅,根据需要执行[_awsSnsClient unsubscribe:unsubscribeRequest]。然后得到下一个100 ......

代码

- (void) awsUsubscribeAllSubscriptions {
    DLog(@"Removing existing subscriptions");

    AWSSNSListSubscriptionsInput *request = [AWSSNSListSubscriptionsInput new];

    __block Boolean sentLastUnsubscribe = NO; // YES when the last unsubscribe request was sent
    __block int pendingUnsubscribe = 0; // Number of outsianding unsubscribes (async process not yet complete)

    do {
        [[[_awsSnsClient listSubscriptions:request] continueWithSuccessBlock:^id(BFTask *task) {
            AWSSNSListSubscriptionsResponse *response = (AWSSNSListSubscriptionsResponse *)task.result;
            NSString *nextToken = response.nextToken;
            NSArray *subscriptions = response.subscriptions;
            for (AWSSNSSubscription *subscription in subscriptions) {
                if ([subscription.endpoint isEqualToString:_awsPlatformEndpoint.endpointArn]) {
                    AWSSNSUnsubscribeInput *unsubscribeRequest = [AWSSNSUnsubscribeInput new];
                    unsubscribeRequest.subscriptionArn = subscription.subscriptionArn;
                    pendingUnsubscribe++;
                    [[[_awsSnsClient unsubscribe:unsubscribeRequest] continueWithSuccessBlock:^id(BFTask *task) {
                        DLog(@"Unsubscribed from:%@",subscription.subscriptionArn);
                        return nil;
                    }] continueWithBlock:^id(BFTask *task) {
                        pendingUnsubscribe--;
                        if (task.error) {
                            // failed with error
                            ALog(@"Error unsubscribing to: %@, %@, %@", subscription, [task.error localizedDescription], [task.error localizedFailureReason]);
                        }
                        // If we have processed the last unsubscribe, then create topics and subscribe
                        if (sentLastUnsubscribe  && (pendingUnsubscribe <= 0)) {
                            [self awsCreateTopicsAndSubscriptions];
                        }
                        return nil;
                    }];
                }
            }
            request.nextToken = nextToken;
            if(!nextToken) sentLastUnsubscribe = YES; // Reached the end of the SNS subscriptions
            return nil;
        }] continueWithBlock:^id(BFTask *task) {
            if (task.error) {
                // failed with error
                ALog(@"Error listing subscriptions: %@, %@", [task.error localizedDescription], [task.error localizedFailureReason]);
            }
            return nil;
        }];
    } while (!sentLastUnsubscribe);
}

有没有更好的方法从端点删除所有SNS订阅?有没有办法在此循环期间强制释放任何保留的数据?

解决方案

使用递归和- waitUntilFinished。内存负载现在更低。

-(void) awsUnsubscribeFromAllSubscriptionsWithNextToken:(NSString *)nextToken AndSubscribe:(BOOL)subscribe {
AWSSNSListSubscriptionsInput *request = [AWSSNSListSubscriptionsInput new];
request.nextToken = nextToken;
[[[_awsSnsClient listSubscriptions:request] continueWithSuccessBlock:^id(BFTask *task) {
    AWSSNSListSubscriptionsResponse *response = (AWSSNSListSubscriptionsResponse *)task.result;
    NSArray *subscriptions = response.subscriptions;
    for (AWSSNSSubscription *subscription in subscriptions) {
        if ([subscription.endpoint isEqualToString:_awsPlatformEndpoint.endpointArn]) {
            DLog(@"Unsubscribe from %@", subscription.topicArn);
            AWSSNSUnsubscribeInput *unsubscribeRequest = [AWSSNSUnsubscribeInput new];
            unsubscribeRequest.subscriptionArn = subscription.subscriptionArn;
            [[_awsSnsClient unsubscribe:unsubscribeRequest] waitUntilFinished];
        }
    }
    if(response.nextToken) {
        [self awsUnsubscribeFromAllSubscriptionsWithNextToken:response.nextToken AndSubscribe:subscribe];
    } else if (subscribe) {
        [self awsCreateTopicsAndSubscriptions];
    }
    return nil;
}] continueWithBlock:^id(BFTask *task) {
    if (task.error) {
        // failed with error
        ALog(@"Error listing subscriptions: %@, %@", [task.error localizedDescription], [task.error localizedFailureReason]);
    }
    return nil;
}];

}

1 个答案:

答案 0 :(得分:0)

请注意- listSubscriptions:是一种异步方法,会立即返回。您正在for循环中调用异步方法。这意味着您可能会在短时间内拨打- listSubscriptions:数百甚至数千次。

您可以做的最简单的事情是在异步块的末尾调用- waitUntilFinished。它使整个方法同步

但是,一般情况下,应尽量避免调用- waitUntilFinishedAWSKinesisRecorderTests.m具有递归调用- getRecords:的功能。你可以采用类似的模式。