jensmeder / DarkLightning

Simply the fastest way to transmit data between iOS/tvOS and OSX
MIT License
333 stars 39 forks source link

JMTaggedPacket, writeData, crash for large files more than 100mb. #12

Closed artem-sherbachuk closed 8 years ago

artem-sherbachuk commented 8 years ago

I use JMTaggedPacket to tagged file that I send. First I get data from file like this:

func sendNetiveMediaFile(it: MediaItem) {
            let mediaURL = root.URLByAppendingPathComponent(it.mediaNativeFilePath)
            if let data = NSFileManager.defaultManager().contentsAtPath(mediaURL.path!) {
                self.send(data, tag: paket.tag)
            }
        }

then it call write:

 func send(data: NSData, tag: UInt16) {
       let paket = JMTaggedPacket(data: data, andTag: tag)!
       let send = coder.encodePacket(paket)
       usb.writeData(send)
}

I use different tags that starts from 1 to 65535.

When JMSocketConnection calls writeData, if file large it crashes with error:

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* NSAllocateMemoryPages(104058079) failed' *\ First throw call stack: (0x2152db8b 0x20ceadff 0x2152dad1 0x21cec0b1 0x21cc39dd 0x21c92c59 0x21c92b73 0x21ca026f 0x21ce4603 0x21ce4465 0xf0107 0xf7855 0x18e970 0x191ac8 0x193a90 0x190a64 0x1934e0 0x190af4 0x1e21f6c 0x193750 0x190260 0x190344 0x1910b8 0x191140 0x18f6c4 0x1e21f6c 0x18ec80 0x18ed80 0xf7bf3 0x2395ba7 0x2395b93 0x239a659 0x214ef7d5 0x214edccf 0x2143c289 0x2143c07d 0x22a58af9 0x25b672c5 0x18df24 0x210e8873) libc++abi.dylib: terminating with uncaught exception of type NSException

screen shot 2016-07-08 at 12 47 49 pm

can you tell me what happens here? I send file from ios to mac and back.

jensmeder commented 8 years ago

Hey!

Well, that's pretty easy to explain: your app ran out of memory 😉. I have to admit that I have never really tried to send huge files even though the packet protocols support files up to 4GB (in theory).

At the moment I try to send the data block all at once. If the underlying stream was unable to write the data I chunk them. I can try to circumvent the issue by not creating a new data buffer for each chunk.

I'll keep you posted.

artem-sherbachuk commented 8 years ago

hey! ok thanks for an explanation :). Also, its will be great if possible to send not only UInt16 tag but also, String in one write. If it possible of corse, for example, encode main data and String as a tag - it can be id "asdkgjalkjgag123951alsd", action description "first.device.send.file.by.id" or whatever. This new protocol can be relly flexible.

thanks.

artem-sherbachuk commented 8 years ago

@jensmeder here is solution found here http://stackoverflow.com/questions/21252258/huge-memory-leaks-nsdata No more crashes.

-(BOOL)writeData:(NSData *)data
{
    if (!data || data.length == 0 || _connectionState != JMSocketConnectionStateConnected)
    {
        return NO;
    }

    NSInteger bytesWritten = [_socket.outputStream write:data.bytes maxLength:data.length];

    while (bytesWritten != data.length) {
        @autoreleasepool {
            NSRange range = NSMakeRange(bytesWritten, data.length - bytesWritten);
            NSData* subData = [data subdataWithRange:range];
            bytesWritten += [_socket.outputStream write:subData.bytes maxLength:subData.length];
        }
    }

    if(bytesWritten > 0)
    {
        return YES;
    }

    return NO;
}
jensmeder commented 8 years ago

Nice! Thanks for sharing. I will incorporate your fix in the next release of DarkLightning this weekend.

jensmeder commented 8 years ago

I have incorporated your fix in version 1.0.1 . Sorry for the delay.