• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

ios - 内存增长之谜(Objective-C)

[复制链接]
菜鸟教程小白 发表于 2022-12-13 08:52:32 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

我的应用程序出现内存增长问题。

自从 在这里描述完整的代码令人生畏, 我将其缩小到这个简单的场景,我在两个 View Controller 之间来回切换以学习基本的内存动态。

 - (void)viewDidLoad {
    [ super viewDidLoad];

for (int i=0; i<100000; i++) { __weak NSString* str = [NSString stringWithFormat"abcsdf"]; str = 无; } }

这应该显示没有内存增长,因为我通过使“str”变为 nil 来分配“str”和取消分配“str”,从而失去了所有者。

但是,内存一直在增长。 每次我加载这个 View Controller 时,内存都会不断增长并且永远不会回来。

谁能告诉我这是为什么? 我正在使用 ARC。



Best Answer-推荐答案


您的代码片段包含一些关于 iOS/OS X 内存管理的有趣内容。

__weak NSString* str = [NSString stringWithFormat"abcsdf"];
str = nil;

没有ARC的代码与以下相同。

NSString* str = [[[NSString alloc] initWithFormat"abcsdf"] autorelease];
str = nil;

因为 stringWithFormat: 类方法不以“alloc”、“new”、“copy”或“mutableCopy”开头。这是命名规则。因此 NSString 对象由 Autorelease Pool 保留。自动释放池可能在主 Runloop 中。因此 NSString 对象没有立即释放。它会导致内存增长。 @autoreleasepool 解决了。

@autoreleasepool {
    __weak NSString* str = [NSString stringWithFormat"abcsdf"];
    str = nil;
}

NSString 对象在 @autoreleasepool 代码块的末尾被释放。

顺便说一句,[NSString stringWithFormat"abcsdf"] 可能不会每次都分配任何内存。原因是它是静态字符串。让我们使用这个类来做进一步的解释。

#import <Foundation/Foundation.h>

@interface Test : NSObject
+ (instancetype)test;
@end

@implementation Test
- (void)dealloc {
    NSLog(@"Test dealloc");
}

+ (instancetype)test
{
    return [[Test alloc] init];
}
@end

这是 __weak 的测试代码。

@autoreleasepool {
    NSLog(@"BEGIN: a = [Test test]\n");
    __weak Test *a = [Test test];
    NSLog(@"END: a = [Test test]\n");
    a = nil;
    NSLog(@"DONE: a = nil\n");
}

代码的结果。

BEGIN: a = [Test test]
END: a = [Test test]
DONE: a = nil
Test dealloc

你说通过使'str'变为nil来释放'str',从而失去所有者。这是不正确的。 a 弱变量没有对象的所有权。自动释放池确实拥有对象的所有权。这就是对象在 @autoreleasepool 代码块末尾被释放的原因。看看这个案例的其他测试代码。

NSLog(@"BEGIN: a = [[Test alloc] init]\n");
__weak Test *a = [[Test alloc] init];
NSLog(@"END: a = [[Test alloc] init]\n");
a = nil;
NSLog(@"DONE: a = nil\n");

您可以从代码中看到编译警告。

warning: assigning retained object to weak variable; object will be
         released after assignment [-Warc-unsafe-retained-assign]
            __weak Test *a = [[Test alloc] init];
                         ^   ~~~~~~~~~~~~~~~~~~~

[[Test alloc] init] 不会将对象注册到自动释放池。好吧,不再需要 @autoreleasepool 了。而 a__weak 变量,所以对象不会被任何东西保留。因此结果是

BEGIN: a = [[Test alloc] init]
Test dealloc
END: a = [[Test alloc] init]
DONE: a = nil

没有所有权就没有生命。该对象在分配后立即被释放。我认为您想编写没有 __weak 的代码,如下所示。

NSLog(@"BEGIN: a = [[Test alloc] init]\n");
Test *a = [[Test alloc] init];
NSLog(@"END: a = [[Test alloc] init]\n");
a = nil;
NSLog(@"DONE: a = nil\n");

结果符合预期。通过将 nil 分配给强变量 a 来释放对象。然后没有人拥有该对象的所有权,该对象被释放了。

BEGIN: a = [[Test alloc] init]
END: a = [[Test alloc] init]
Test dealloc
DONE: a = nil

关于ios - 内存增长之谜(Objective-C),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31176061/

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝2

帖子830918

发布主题
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap