使用托管动态存储对一个简单程序进行Segfaulting

时间:2014-02-03 20:23:51

标签: objective-c gnustep

我试过问过几个我认识的人,但他们可能太忙了,无法就此提出建议。

我一直在使用alloc / dealloc的方式进入墙 用。下面的一个让我疯狂......这是一个简单的本质 我一直试图调试的一些代码。

以下是我认为应该发生的事情(但显然不是):

  • 我分配了一个游泳池
  • 我创建了一个对象并自动释放以将其放入当前池中 当我释放游泳池时它会释放。
  • 测试类的NSString var只是内部的。
  • NSString在该类的dealloc方法中发布。
  • 我发布了试图释放测试对象的池,
  • 一旦尝试释放,就会在dealloc方法中出现段错误 的NSString。

在过去,我设法通过摆弄来购买,直到问题消失。但是,我现在已经达到了发展的程度,我需要能够证明我已经消除了存储问题。

去年我读过大量关于ObjC存储管理的文档。 不幸的是,似乎在这一切实际上如何适应方面存在一些分歧 这些混乱对我们这些没有参与的人没有帮助 随着它的发展,这个托管存储过程。如果我遇到困难(我曾经在RTOS的汇编代码中编写DSA),我只能想象其他人必须面对的问题。

一个非常有用的东西是关于如何测试代码以消除的手册 这种错误。我确信这样的信息存在,并且在这里有点碰到,但是这些碎片并不是整齐地融合在一起。我也一直在使用enableDoubleReleaseCheck。

我把它留下来以保持测试用例的简单。

这是CommandTest.m,一个完整的测试用例,结果如下:

./CommandTest
Release cmdline
Segmentation fault (core dumped)


/* Makefile strings:
   OBJC = gcc -g -fobjc-exceptions -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS -I /usr/include/GNUstep

   CommandTest:    CommandTest.o $(OBJC) -g -o CommandTest CommandTest.o -lobjc -lgnustep-base */

#include <stdio.h>

import

@interface Command:NSObject {NSString *cmdline;}
- (id)   init;
- (void) dealloc;
@end

@implementation Command
- (id) init {
  if (!(self = [super init])) {return nil;}
  cmdline = [NSString stringWithCString: "This is a test"];
  return self;
}

- (void) dealloc {
  printf ("Release cmdline\n");
  [cmdline release];
  printf ("Release cmdline done\n");
  [super dealloc];
}
@end

int main( int argc, char *argv[] ) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  Command *cmd            = [[Command new] autorelease];

  @try {[pool release];}
  @catch (NSException *e){
    printf ("Fatal [%s] %s\n", [[e name] cString], [[e reason] cString]);}

  printf ("Done\n");
  exit (EXIT_SUCCESS);
}

建议将 欢迎并非常感谢。

2 个答案:

答案 0 :(得分:2)

你的字符串被双重释放。 +[NSString stringWithCString:]创建一个自动释放的对象。它会自动放入最近的自动释放池中。

释放池时,字符串也是如此。然后,字符串的所有者再次发送release,这会导致您的异常。 (这两个实际上可能以任何顺序发生;无关紧要。)

从引用计数的角度来看,您的Command对象实际上并不拥有该字符串,因为它没有遵循NARC规则。它未在字符串中使用任何newallocretaincopy。自动释放池是唯一的所有者。因此,Command以后发送release是错误的。

解决方案是在创建时将retain发送到自动释放的字符串 - 然后池和Command都拥有所有权,并且需要稍后发送release - 或使用alloc创建,如[[NSString alloc] initWithCString:]中所示。然后Command将是唯一所有者。

答案 1 :(得分:1)

问题出在这里:

cmdline = [NSString stringWithCString: "This is a test"];

你没有保留这个对象,所以它有效地返回0保留计数并且很快就会自动释放。