9

我发现 NSString 有一个奇怪的行为。我尝试运行以下代码并注意到了这一点。

NSString *str = [[NSString alloc] initwithstring : @"hello"];
[str release];
NSLog(@" Print the value : %@", str);

在这里,在第三行应用程序应该崩溃,因为我们正在访问一个已释放的对象。但它正在打印 str 的值。它没有崩溃。但是使用 NSArray 我观察到了不同的行为。

NSArray *array = [[NSArray alloc] initwithobjects : @"1",  @"2", nil];
[array release];
NSLog(@"Print : %@", [array objectatindex : 0]);
NSLog(@"Print : %@", [array objectatindex : 0]);

该代码有两个用于 NSArray 的 NSLog 语句。这里在执行第一个NSLog时释放后,是打印值。但是当执行第二个 NSLog 时,应用程序崩溃了。应用程序崩溃是可以接受的,因为访问的数组已经被释放。但是在执行第一个 NSLog 时它应该会崩溃。不是第二个。

帮助我解决这些行为。在这些情况下发布如何工作。

谢谢吉腾

4

5 回答 5

7

第一个示例不会崩溃,因为字符串文字永远不会被释放。代码真的是:

NSString *str = @"hello";
[str release];

人们在内存管理上被字符串文字所困扰,并错误地使用==来比较它们而不是isEqualToString:. 编译器做了一些导致误导性结果的优化。

更新

下面的代码证明了我的观点:

    NSString *literal = @"foo";
    NSString *second = [NSString stringWithString:literal];
    NSString *third = [NSString stringWithString:@"foo"]; // <-- this gives a compiler warning for being redundant
    NSLog(@"literal = %p", literal);
    NSLog(@"second = %p", second);
    NSLog(@"third = %p", third);

此代码提供以下输出:

2013-02-28 22:03:35.663 SelCast[85617:11303] 文字 = 0x359c
2013-02-28 22:03:35.666 SelCast[85617:11303] 秒 = 0x359c
2013-02-28 22:03:35.668 选择85617:11303] 第三 = 0x359c

请注意,所有三个变量都指向同一个内存。

于 2013-03-01T04:51:47.397 回答
6

您的第二个示例在第二个崩溃,NSLog因为在第一个日志中,内存array没有被重新使用,但是第一个日志导致堆上的足够活动导致内存被其他东西使用。然后,当您尝试再次访问它时,您会崩溃。

每当一个对象被释放并且它的内存被标记为空闲时,就会有一段时间该内存仍然存储该对象的剩余内容。在此期间,您仍然可以在此类对象上调用方法等,而不会崩溃。这个时间非常短,如果你运行了很多线程,它甚至可能不足以让你的方法调用。所以很明显,不要依赖这个实现细节来进行任何行为。

正如其他人所说,关于您的第一个问题,NSString文字不会被释放。这对于其他一些 Foundation 类是正确的(NSNumber想到),但也是一个实现细节。如果您需要对内存管理进行实验,请改用NSObject实例,因为它不会显示异常行为。

于 2013-03-01T05:05:59.917 回答
4

当您在对象上发送release消息时,该对象实际上并没有从内存中删除。释放消息只是将引用计数减一。如果引用计数为零,则该对象被标记为空闲。然后系统将其从内存中删除。在此释放发生之前,您可以访问您的对象。即使您release是对象,您的对象指针仍然指向该对象,除非您分配nil给该指针。

于 2013-03-01T04:51:29.750 回答
0

第一个示例不会崩溃,因为字符串文字永远不会被释放。第二个完全取决于释放和保留计数器。

阅读这篇文章。它包含对您的查询的简短说明

你应该阅读这个苹果指南

于 2013-03-01T04:56:44.980 回答
0

您似乎认为release应该立即销毁该对象。我不认为这是语言做出的保证。意思release是:我已经用完了这个对象,我保证不再使用它。从那时起,由系统决定何时实际释放内存。

您看到的任何超出此范围的行为都未定义,并且可能会从 Objective C 运行时的一个版本更改为下一个版本。

也就是说,其他表明区别在于字符串文字和内存重用的答案目前是正确的,但假设行为总是这样可能是一个错误。

于 2013-03-01T09:40:17.010 回答