避免记忆垃圾

时间:2011-02-17 09:18:06

标签: cocoa macos garbage-collection

我正在使用垃圾收集的Mac应用程序。应用程序崩溃了一些用户,崩溃日志表明它与内存损坏或内存丢失有关。

我发布了以下崩溃日志的重要部分。

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000
Crashed Thread:  0  Dispatch queue: com.apple.main-thread

Application Specific Information:
objc[81831]: garbage collection is ON

Thread 0 Crashed:  Dispatch queue: com.apple.main-thread

0   libSystem.B.dylib                  0x00007fffffe00847 __memcpy + 167
1   libauto.dylib                      0x00007fff82718170 auto_zone_write_barrier_memmove + 96
2   libauto.dylib                      0x00007fff8271916e auto_realloc(_malloc_zone_t*, void*, unsigned long) + 878
3   libSystem.B.dylib                  0x00007fff8346e0db malloc_zone_realloc + 92
4   com.apple.Foundation               0x00007fff83169836 _NSMutableDataGrowBytes + 652
5   com.apple.Foundation               0x00007fff83169513 -[NSConcreteMutableData appendBytes:length:] + 101
6   MY.Application                     0x000000010000b9cd -[Connection stream:handleEvent:] + 376
7   com.apple.CoreFoundation           0x00007fff85742373 _signalEventSync + 115
8   com.apple.CoreFoundation           0x00007fff857422e4 _cfstream_solo_signalEventSync + 116

发生的情况是,我的应用程序从网络接收数据并将该数据写入NSMutableData对象。我和其他一些开发人员讨论了这个问题,我们最好的猜测是内存被破坏,导致崩溃。

问题是如何防止内存垃圾,以及如何在Xcode中调试这样的错误?

为了完整起见,我还发布导致崩溃的方法代码。

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
    switch(eventCode) {
          case NSStreamEventHasSpaceAvailable: {
               if (stream == outputStream) {
                    [self writeBufferToStream];
               }
               break;
          }

          case NSStreamEventOpenCompleted:
            if (stream == inputStream) {
               readReady = YES;
            } else {
               writeReady = YES;
            }

            if ([self isReadyForUse] && [delegate respondsToSelector:@selector(connectionReadyForUse:)])
               [delegate connectionReadyForUse:self];
            break;

        case NSStreamEventHasBytesAvailable: {
               if (stream == inputStream) {
                    int bytesRead = 0;

                    static uint8_t buffer[kBufferSize];
                    bytesRead = [inputStream read:buffer maxLength:sizeof(buffer)];
                    [inBuffer appendBytes:buffer length:bytesRead];

                    //** Process buffer contents **//

                    BOOL safe = YES;

                    while (safe) {
                         if (inSize <= 0) {
                              if ([inBuffer length] >= sizeof(uint64_t)) {
                                   memcpy(&inSize, [inBuffer bytes], sizeof(uint64_t));
                                   NSRange rangeToDelete = {0, sizeof(uint64_t)};
                                   [inBuffer replaceBytesInRange:rangeToDelete withBytes:NULL length:0];

                              } else {
                                   break;
                              }
                         }

                         if (inSize > 0) {
                              if ([inBuffer length] >= inSize) {
                                   NSMutableData *packetData = [NSMutableData dataWithBytes:[inBuffer bytes] length:inSize];                                        
                                   [delegate connection:self receivedData:packetData];

                                   safe = NO;

                                   NSRange rangeToDelete = {0, inSize};
                                   [inBuffer replaceBytesInRange:rangeToDelete withBytes:NULL length:0];
                                   inSize = 0;
                              } else {
                                   break;
                              }
                         } else {
                              break;
                         }
                    }
               }
            break;
               }

        case NSStreamEventErrorOccurred: {

            NSError *theError = [stream streamError];
            if (stream == inputStream)
                if (delegate && [delegate respondsToSelector:@selector(connection:encounteredReadError:)])
                    [delegate connection:self encounteredReadError:theError];
                else{
                    if (delegate && [delegate respondsToSelector:@selector(connection:encounteredWriteError:)])
                        [delegate connection:self encounteredWriteError:theError];   
                }
            break;
        }

        case NSStreamEventEndEncountered: {
            if (delegate && [delegate respondsToSelector:@selector(connectionDisconnected:)])
                [delegate connectionDisconnected:self];

            readReady = NO;
            writeReady = NO;
            break;
          }

        default:
            break;
    }
}

1 个答案:

答案 0 :(得分:-1)

保持数据在同一线程中读写。如果必须在多线程中执行此操作,则可以选择锁或屏障以确保该线程安全