【问题标题】:Connective C with ARC relishing objects in background连接 C 与背景中的 ARC 津津乐道对象
【发布时间】:2014-12-29 06:31:20
【问题描述】:

背景 我来自 C 背景,发现放弃手动内存管理非常痛苦。旧的目标 c 保留和发布模型虽然有点笨拙,但还可以。

我编写了一个 osX 应用程序,它从大小未知的未指定数据源读取数据,并对数据进行可视化呈现。为了给应用程序施加压力,我生成了一个非常大的数据集,该数据集在不到 3 分钟的时间内生成了超过一亿个对象(时间是一个猜测),但是当我删除包含具有亿个对象的可变数组的视图时,应用程序海滩球释放对象。我通过将数组传递给执行释放的后台线程解决了这个问题。无论如何,我不得不重新设计应用程序,以便它可以被沙盒化,我决定使用 ARC,现在我又回到了同样的压力测试,沙滩球又回来了。有没有办法让后台线程释放在 ARC 下创建的对象,或者我是否需要返回非 ARC 设计,如果我想用 Swift 重新编写应用程序怎么办。

问候克里斯蒂安·安徒生

【问题讨论】:

  • 是否可以向您的代码显示对象是如何分配的?
  • ARC 代码的行为与 MRC 代码不同,这没有根本原因 - 您只是将内存管理调用的手动插入替换为自动插入。检查您是否没有意外地在主线程中保留对大型数组的引用 - 在 MRC 下,当您在后台线程中释放时可能会导致悬空引用,可能会出现问题,但如果您不使用它则不会,但在ARC 这样的引用会阻止释放。

标签: objective-c automatic-ref-counting release


【解决方案1】:

有没有办法让后台线程释放在 ARC 下创建的对象

是的。只需将 nil 分配给后台线程上的变量。但是您应该确保该变量是唯一一个引用该值的变量。

#import <Foundation/Foundation.h>
#import <pthread.h>

pthread_t g_mainThread;

@interface Test : NSObject
@end

@implementation Test
- (void)dealloc
{
    NSLog(@"Test %p was dealloced on %s", self,
        g_mainThread == pthread_self() ? "the main queue" : "global queue");
}
@end

//主要

int main()
{
    g_mainThread = pthread_self();

    NSMutableArray *array = [[NSMutableArray alloc] init];
    for (int i = 0; i < 10; ++i) {
        Test *test = [[Test alloc] init];
        [array addObject:test];
    }

    __block NSMutableArray *arrayOnGlobalQueue = array;

    /*
     * The array object was referenced from *array* and *arrayOnGlobalQueue* variables.
     * The reference count of the array object is 2.
     */

    array = nil;

    /*
     * The *array* variable doesn't refer the array object any more.
     * The reference count of the array object is 1.
     */

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_async(queue, ^{

        /*
         * Assign nil to the variable for releasing the array object
         */

        arrayOnGlobalQueue = nil;

        /*
         * The *arrayOnGlobalQueue* variable doesn't refer the array object any more.
         * The reference count of the array object is 0.
         * Thus the array object was dealloced on the background thread(queue).
         */

    });

    dispatch_main();

    return 0;
}

结果是这样的。

Test 0x7f96aac033b0 was dealloced on global queue
...

但是,一般情况下,AutoreleasePool引用对象,AutoreleasePool在主线程释放对象。

例如,如果你使用 NSMutableArray +array 类方法来实例化数组对象而不是 +alloc 和 -init 方法,

NSMutableArray *array = [NSMutableArray array];
// NSMutableArray *array = [[NSMutableArray alloc] init];

表示数组对象注册到自动释放池。因此,数组对象的引用计数为 2。使用@autoreleasepool 可以避免这种情况。

我是否需要返回非 ARC 设计

在非 ARC 下使用 release 而不是将 null 分配给 ARC 下的变量。

如果我想用 Swift 重新编写应用程序怎么办

与 Objective-C 完全一样。

【讨论】:

  • 感谢它正是我正在寻找的解决方案,我有点接近那个解决方案,但它还没有工作。我正在使用 +alloc -init 你是说我更适合使用 +array 吗?
  • 真正起作用的唯一问题是,如果我通过数组说我的应用程序控制器释放数据,那么在后台执行完成之前,显示数据的对象不会消失。我想在后台线程中发布数据的原因是我可以清理 UI 并继续下一个演示文稿,而不必等待 180 亿个对象发布任何建议
  • 我看到的最后一条消息是 CoreAnimation: warning, deleted thread with uncommitted CATransaction;在环境中设置 CA_DEBUG_TRANSACTIONS=1 以记录回溯。我会做明显的回溯,但我认为我需要将数组传递给一个我不会去皮的对象
  • 等等,你想在后台线程上释放 UIView 对象吗? UIKit 不是线程安全的,所以不可能。
  • 不不,它们不是 UIView,而是 NSMutableArrays 中的 NSMutableArray 中的 NSStrings
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-10
  • 2014-02-27
  • 2014-09-18
  • 2022-11-28
  • 1970-01-01
相关资源
最近更新 更多