【问题标题】:Apple's reachability memory leak苹果的可达性内存泄漏
【发布时间】:2014-01-06 06:29:36
【问题描述】:

我在我的非弧项目中使用苹果的 Reachabilry 类。当我用仪器运行它来查找内存泄漏时,它指的是可达性方法。问题来了:

+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;
{
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);

    WReachability* returnValue = NULL;

    if (reachability != NULL)
    {
        returnValue = [[self alloc] init];
        if (returnValue != NULL)
        {
            returnValue->reachabilityRef = reachability;
            returnValue->localWiFiRef = NO;
        }
    }
    return returnValue;
}

泄露的对象是可达性和returnValue。 我知道 SCNetworkReachabilityCreateWithAddress 创建了一个新实例,我必须 CFRelease 它,但它发生在 dealloc 中!

- (void)dealloc
{
    [self stopNotifier];
    if (reachabilityRef != NULL)
    {
        CFRelease(reachabilityRef);
    }
    [super dealloc];
}

那么我该怎么做才能避免这里的内存泄漏?

更新: 也许问题在于如何调用可达性?我用这个方法:

+ (instancetype)reachabilityForInternetConnection;
{
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    return [self reachabilityWithAddress:&zeroAddress];
}

然后我这样调用可达性:

[[Reachability reachabilityForInternetConnection] startNotifier];

并且不要将它分配给任何对象,只需使用这一行。 我试图将此调用更改为:

Reachability *reachability = [[Reachability reachabilityForInternetConnection] autorelease];
[reachability startNotifier];

但是在这个分析器告诉我“autorelease 太多”之后。

【问题讨论】:

    标签: ios objective-c xcode memory-leaks reachability


    【解决方案1】:

    @Alexart 回答对我有用,但如果您想要简化版本,请使用

    +(instancetype)reachabilityWithAddress:(void *)hostAddress
    {
       SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
       if (ref)
       {
          id reachability = [[self alloc] initWithReachabilityRef:CFBridgingRetain((__bridge id)ref)];
          CFRelease(ref);
          return reachability;
       }
       return nil;
    

    }

    【讨论】:

      【解决方案2】:

      我认为下一个方法更好:

      + (Reachability*) reachabilityWithHostName: (NSString*) hostName;
      {
          Reachability* retVal = NULL;
          SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
          if(reachability!= NULL)
          {
              retVal= [[self alloc] init];
              if(retVal!= NULL)
              {
                  retVal->reachabilityRef = reachability;
                  retVal->localWiFiRef = NO;
              }
              else
              {
                  CFRelease(reachability);
              }
          }
          return retVal;
      }
      

      【讨论】:

        【解决方案3】:

        如果 returnValue 等于 NULL 可达性对象被泄露,你应该在这种情况下释放它。同样根据 Cocoa 命名约定 (https://developer.apple.com/library/ios/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-SW1),您必须返回自动释放的对象:

        + (instancetype)reachabilityWithAddress:
        {
            ...
             returnValue = [[[self alloc] init] autorelease];
        

        如果您不想返回自动释放的对象,或者将方法重命名为从新开始:newReachabilityWithAddress 或类似的名称。

        尝试在 Xcode 中运行静态分析器,它可以帮助发现问题。

        【讨论】:

        • 和analyzer & arc 也依赖于命名约定
        • Daij-Djan,你能解释一下吗?
        • 是的,看起来它有效,非常感谢!最后一个问题是:为什么没有人注意到可达性的错误?非常有名的课程,也上传到苹果官方wep-page (developer.apple.com/Library/ios/samplecode/Reachability/…)。
        • 我不知道如何在 Apple 中编写示例代码,但它经常包含错误。因此,仅将其用作主要原理的说明,不要盲目地将其复制粘贴到您的项目中。如果您想更正错误,您可以通过您的开发者帐户在bugreport.apple.com 填写错误报告。
        • 从苹果下载最新的可达性代码。此泄漏在更新的代码中处理 (developer.apple.com/library/ios/samplecode/Reachability/…)
        【解决方案4】:

        启用 ARC 的解决方案Reachability 类。

        1. 在问题行下方添加CFAutorelease(ref)
        2. dealloc 中删除CFRelease(self.reachabilityRef) 代码

        更新dealloc

        - (void)dealloc {
            [self stopNotifier];
        
            self.reachableBlock          = nil;
            self.unreachableBlock        = nil;
            self.reachabilityBlock       = nil;
            self.reachabilitySerialQueue = nil;
        }
        

        更新reachabilityWithAddress

        + (instancetype)reachabilityWithAddress:(void *)hostAddress {
            SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
            if (ref) {
                id reachability = [[self alloc] initWithReachabilityRef:ref];
                CFAutorelease(ref);
                return reachability;
            }
        
            return nil;
        }
        

        更新reachabilityWithHostname

        + (instancetype)reachabilityWithHostname:(NSString*)hostname {
            SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);
            if (ref) {
                id reachability = [[self alloc] initWithReachabilityRef:ref];
                CFAutorelease(ref);
                return reachability;
            }
        
            return nil;
        }
        

        【讨论】:

          【解决方案5】:

          最新的reachability.m 似乎需要ARC,我的应用没有使用它。

          我刚刚打开它:

          1. 转到目标\构建阶段\编译源代码

          2. 找到可达性并双击它

          3. 添加-fobjc-arc

          内存泄漏现在消失了

          【讨论】:

            【解决方案6】:

            在dealloc中除了CFRelease外,对代码的正确修复如下。

            看看下面的代码主体。类似的主体也需要进入reachabilityWithHostName 代码。

            + (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress
            {
                SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);
            
                Reachability* returnValue = NULL;
            
                if (reachability != NULL)
                {
                    returnValue = [[self alloc] init];
                    if (returnValue != NULL)
                    {
                        returnValue->_reachabilityRef = CFRetain(reachability);
                        returnValue->_alwaysReturnLocalWiFiStatus = NO;
                    }
                     CFRelease(reachability);
                }
                return returnValue;
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-12-04
              • 2011-03-04
              • 2015-08-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-29
              • 1970-01-01
              相关资源
              最近更新 更多