– 抛出一个exception,说长度太大,但事实并非如此

我使用NSInputStream从文件中读取数据。 如果maxLength大于49152,它将崩溃。

当它崩溃时 – 有时候,但不是每次都崩溃,它会给出这样的信息:

***由于未捕获的exception’NSInvalidArgumentException’终止应用程序,原因:’*** – [NSConcreteData initWithBytes:length:copy:freeWhenDone:bytesAreVM:]:荒谬长度:4294967295,最大大小:2147483648字节’

根据我的计算,524288仍然小于该最大值,并且可以适合返回值。 我错过了什么?

 - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { switch (eventCode) { case NSStreamEventHasBytesAvailable: { NSInteger bufferSizeNumber = 524288; //this one will crash. // NSInteger bufferSizeNumber = 491520; // this one will work. uint8_t buf[bufferSizeNumber]; unsigned int len = 0; len = [_stream read:buf maxLength:bufferSizeNumber]; //crashing at this line // more code ... } // more code... } } 

编辑:(我认为这是该行为的关键部分)

如果我在后台线程中“启动”,则bufferSizeNumber的行为如上所述。 但是如果我在主线程中“启动”,则bufferSizeNumber在崩溃之前可以达到943713。

 - (void)start { _stream.delegate = self; [_stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [_stream open]; [[NSRunLoop currentRunLoop] run]; } 

你的问题是所谓的“堆栈溢出”(你之前可能听说过)。

您的方法使用可变长度数组在堆栈上分配缓冲区:

 uint8_t buf[bufferSizeNumber]; 

当缓冲区的大小太大而溢出当前堆栈的大小时,行为是不确定的。 未定义的行为可能会导致崩溃或只是按预期工作:只是您正在观察的内容。

512kB是一个巨大的缓冲区,尤其是在iOS上,后台线程的堆栈大小正是这样。

你应该在堆上分配它:

 NSInteger bufferSizeNumber = 524288; NSMutableData *myBuffer = [NSMutableData dataWithLength:bufferSizeNumber]; uint8_t *buf = [myBuffer mutableBytes]; unsigned int len = 0; len = [_stream read:buf maxLength:bufferSizeNumber]; // more code ...