CoreMIDI and Memory Leaks

I recently wrote a “MIDIChimes” app that sends note-on and off somewhat randomly for a given set of notes. I noticed a memory leak, investigated, and after many hours of poking at it finally plugged the leak.

AFAIK there are no Swift code examples out there on the Internet that get this right currently. There are generally two of these things wrong:

  • A MIDIPacket is needlessly allocated
  • No attempt to free the UnsafeMutablePointers is made
  • -or-

  • destroy() is used to free the UnsafeMutablePointers

Here’s an example send() routine that doesn’t leak.

	func send(bytes: [UInt8]) {
		let packetList = UnsafeMutablePointer.alloc(1)
		
		var packet = MIDIPacketListInit(packetList);
		packet = MIDIPacketListAdd(packetList, 1024, packet, 0, bytes.count, bytes);
		
		if (packet == nil ) {
			Swift.print("MIDIPacketListAdd failed.")
		} else {
			MIDIReceived(portRef, packetList)
		}
		
		packetList.dealloc(1)
		
	}

I ran this for 500000 iterations and the memory didn’t ramp up at all. I ran “Instruments” Leaks and came up clean. (I will have to blog about Instruments. It’s pretty cool, but I don’t have much experience with it yet).

A few points –

  • There is no need to allocate a ‘packet’ UnsafeMutablePointer. What you need gets returned by the MIDIPacketListInit and MIDIPacketListAdd routines.
  • The third arg to MIDIPacketListAdd is a timestamp, and usually I see mach_absolute_time() there in example code, but I don’t think it makes any difference when the packetList is going to MIDIReceived. In particular, picking a future timestamp won’t make the MIDI data go out at that moment. As far as I can tell, it goes out immediately upon calling MIDIReceived.
  • destroy() doesn’t appear to free the memory allocated by UnsafeMutablePointer.alloc(1); dealloc(1) is needed. I need to do more web searches on this to see how well this is documented. Certainly there is some info out there that’s wrong on this subject.
  • My treatment of the ‘packet’ return value above is sloppy and I apologize. This blog is about the memory leak though.

ADDENDUM, 1/31/2016 —
There was a memory leak on my read side too. After digging around on the internet for awhile I’ve come up with an answer:

func readProc(pktlist : UnsafePointer,
	readProcRefCon : UnsafeMutablePointer,
	srcConnRefCon : UnsafeMutablePointer)
{
	let list = pktlist.memory
	let count = list.numPackets
	
	var p = list.packet
	for _ in 0..) -> MIDIPacket in
			let p2 = MIDIPacketNext(pp)
			return p2.memory
		})
	}
}

You can’t pass &p into MIDIPacketNext() directly. You have to use this withUnsafePointer widget. Whatever it takes, I guess.

The closure could be written more succinctly but this way it’s easy to see what’s happening.

Leave a Reply

Your email address will not be published. Required fields are marked *