【问题标题】:Cocoa Memory Issue, Memory doesn't get reclaimed when objects are removed from arrayCocoa 内存问题,从数组中删除对象时不会回收内存
【发布时间】:2012-04-18 21:29:25
【问题描述】:

我有一个保留/发布项目,它有一个简单的算法。我从一个 100000 个对象的可变数组开始,每隔 5 秒我在开始时删除 1000 个对象并在最后添加 1000 个对象。从理论上讲,我的内存占用应该在 Lil 延迟后保持不变,但是它会持续上升,直到达到一定数量。但是用“[array removeAllObjects]”删除它的所有对象并释放数组并不会回收所有内存,只是一部分。我在发布方案中运行,没有调试器,并使用活动监视器来跟踪内存使用情况。

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
    array = [[NSMutableArray alloc] init];
    for(int i = 0; i<100000; i++){
        NSURL *url = [NSURL URLWithString:@"http://www.apple.com"];
        [array addObject:url];
    }
    self.t = [NSTimer scheduledTimerWithTimeInterval:10  target:self selector:@selector(addAndRemove:) userInfo:nil repeats:YES];

}

-(IBAction)addAndRemove:(id)sender{
     [array removeObjectsInRange:NSMakeRange(0, 1000)];

     for(int i = 0; i<1000; i++){
        NSURL *url = [NSURL URLWithString:@"http://www.apple.com"];
        [array addObject:url];
     }
}

-(IBAction)clear:(id)sender {
    [array removeAllObjects];    
    [array release];
    [t invalidate];
    t = nil;
}

【问题讨论】:

    标签: objective-c xcode macos cocoa osx-lion


    【解决方案1】:

    使用 Activity Monitor 监控您的内存使用情况非常不可靠。首先,你在看哪个内存领域(虚拟私有内存、真实私有内存、真实共享内存或真实内存)?

    其次,当您的代码发出分配请求时,通常会直接或间接地发送到 malloc 例程。 malloc 例程尝试从它已经拥有的内存中满足您的请求。如果它不能,那么它会向系统请求更多。当您释放内存时,它会返回到 malloc。 Malloc 不一定会将其返回给系统。它可以让它更快地满足未来的请求。因此,您可能不会看到进程的内存使用量下降,至少不会一直下​​降,即使您的程序正在释放它分配的所有内容。

    检查程序是否正确管理内存的正确方法是将 Instruments 与 Leaks and Allocations 工具结合使用。

    【讨论】:

    • 我会做一个强有力的声明;使用 AM 监控内存使用情况是完全没有用的,除非是为了赶上失控的增长。
    • 我正在查看实际内存大小。我已经使用了泄漏工具,并且没有任何内存泄漏。使用分配工具时应该注意什么?
    • 我在分配工具中做了一个测试,它表现正确。活动监视器就像你们说的那样非常不准确。
    • @Ken For 'Malloc 不一定会将其返回给系统。'。你有关于这种行为的任何参考资料吗?
    • @teerapap 暂时没有具体的参考资料。它广为人知,也许网络搜索会为您找到它。 malloc() 的工作方式与系统 VM 通过 vm_allocate() 的分配方式的工作方式也是固有的。 malloc() 允许任何大小的分配。 vm_allocate() 一次分配一个页面(参见getpagesize())。所以,如果你malloc()一堆小缓冲区,它们很可能都来自同一个页面,这是来自系统内存的一个分配。如果您随后释放其中一些空间,则无法将空间归还给系统,因为其中的一部分仍在使用中。
    【解决方案2】:

    当你使用创建你的 NSURL 时

    NSURL *url = [NSURL URLWithString:@"http://www.apple.com"];
    

    您正在创建一个自动释放的对象。自动释放的对象存储在自动释放池中,并且仅在该池清空时才被销毁。当主运行循环触发时,主池每 60 秒刷新一次,因此您的对象释放的时间可能比您预期的要晚。

    尝试将您的 for 循环包装在 @autoreleasepool { } 块中,以便立即刷新循环内创建的任何自动释放对象,或者使用 alloc/init 创建您的 NSURL,使其不会自动释放,例如

    NSURL *url = [[NSURL alloc] initWithString:@"http://www.apple.com"];
    

    然后看看这是否会改变你的内存使用情况。

    【讨论】:

    • 主池不会“每 60 秒刷新一次”;每次应用程序处理一个事件时,应用程序对象都会清空它的池并用一个新的替换它。 (是的,这可能会影响长时间运行的后台应用程序。)此外,最好使用 Instruments 通知您的内存优化,而不是在随机的代码行中盲目测试。
    • 我并不是建议将其作为一种内存优化策略,而是作为一种可能的解释,即为什么在销毁数组时内存没有被释放。不过,我接受 Ken 的回答似乎更有可能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    • 2023-03-04
    • 2014-06-27
    • 1970-01-01
    • 2018-08-11
    相关资源
    最近更新 更多