70360

Memory Leak - Not Sure How/Where to CFRelease() CFSet

Question:

I'm yet again struggling with a memory leak, and need some help figuring this one out. I know (or am pretty sure) the CFSet(s) are the problem here.

I assume I need to CFRelease() them, but am not sure how to accomplish this since I also need to return a CFSet in USBDeviceCount(). Any help would be appreciated! Thank you!

Here's the code (which seemingly works great! except for the leaks):

// New USB device has been added (callback function) static void Handle_DeviceMatchingCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef){ // Log the device ID & device count NSLog(@"\nNew USB device: %p\nDevice count: %ld", (void *)inIOHIDDeviceRef, USBDeviceCount(inSender)); } // USB device has been removed (callback function) static void Handle_DeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef){ // Log the device ID & device count NSLog(@"\nUSB device removed: %p\nDevice count: %ld", (void *)inIOHIDDeviceRef, USBDeviceCount(inSender)); } // Counts the number of devices in the device set (includes all USB devices that match dictionary) static long USBDeviceCount(IOHIDManagerRef HIDManager) { // The device set includes all USB devices that match our matching dictionary. Fetch it. CFSetRef devSet = IOHIDManagerCopyDevices(HIDManager); // The devSet will be NULL if there are 0 devices, so only try to count the devices if devSet exists if(devSet) return CFSetGetCount(devSet); // There were no matching devices (devSet was NULL), so return a count of 0 return 0; } - (void) applicationDidFinishLaunching:(NSNotification *)aNotification { // Create an HID Manager IOHIDManagerRef HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); // Create a Matching Dictionary CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // Specify a device manufacturer in the Matching Dictionary CFDictionarySetValue(matchDict, CFSTR(kIOHIDTransportKey), CFSTR("USB")); // Register the Matching Dictionary to the HID Manager IOHIDManagerSetDeviceMatching(HIDManager, matchDict); // Register a callback for USB device detection with the HID Manager IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, &Handle_DeviceMatchingCallback, NULL); // Register a callback fro USB device removal with the HID Manager IOHIDManagerRegisterDeviceRemovalCallback(HIDManager, &Handle_DeviceRemovalCallback, NULL); // Register the HID Manager on our app’s run loop IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); // Open the HID Manager IOReturn IOReturn = IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone); if(IOReturn) NSLog(@"IOHIDManagerOpen failed."); // Couldn't open the HID manager! CFSetRef devSet = IOHIDManagerCopyDevices(HIDManager); CFRelease(devSet); CFRelease(matchDict); }

<a href="https://i.stack.imgur.com/oq48l.png" rel="nofollow"><img alt="leaks" class="b-lazy" data-src="https://i.stack.imgur.com/oq48l.png" data-original="https://i.stack.imgur.com/oq48l.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

<strong>For completeness, here is the solution I was able to implement with Carl's help (thanks, Carl!!):</strong>

AppDelegate.h:

- (void) updateConnectedUSBs; @property(retain) __attribute__((NSObject)) IOHIDManagerRef hidManager; @property (strong) NSSet *usbDeviceSet;

AppDelegate.m:

// New USB device has been added (callback function) static void Handle_DeviceMatchingCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef){ AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate]; [appDelegate updateConnectedUSBs]; } // USB device has been removed (callback function) static void Handle_DeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef){ AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate]; [appDelegate updateConnectedUSBs]; } - (void) updateConnectedUSBs { CFSetRef devSet = IOHIDManagerCopyDevices(_hidManager); self.usbDeviceSet = CFBridgingRelease(devSet); NSLog(@"%@",self.usbDeviceSet); } - (void) applicationDidFinishLaunching:(NSNotification *)aNotification { _hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); // Create a Matching Dictionary CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // Specify a device manufacturer in the Matching Dictionary CFDictionarySetValue(matchDict, CFSTR(kIOHIDTransportKey), CFSTR("USB")); // Register the Matching Dictionary to the HID Manager IOHIDManagerSetDeviceMatching(_hidManager, matchDict); // Register a callback for USB device detection with the HID Manager IOHIDManagerRegisterDeviceMatchingCallback(_hidManager, &Handle_DeviceMatchingCallback, NULL); // Register a callback fro USB device removal with the HID Manager IOHIDManagerRegisterDeviceRemovalCallback(_hidManager, &Handle_DeviceRemovalCallback, NULL); // Register the HID Manager on our app’s run loop IOHIDManagerScheduleWithRunLoop(_hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); // Open the HID Manager IOReturn IOReturn = IOHIDManagerOpen(_hidManager, kIOHIDOptionsTypeNone); if(IOReturn) NSLog(@"IOHIDManagerOpen failed."); // Couldn't open the HID manager! CFRelease(matchDict); }

<a href="https://i.stack.imgur.com/kPLQ8.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/kPLQ8.png" data-original="https://i.stack.imgur.com/kPLQ8.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

Answer1:

You need to store the count before releasing the set. (This was the way all NSObject subclasses worked before ARC, via the -release method.)

if (devSet) { long count = (long)CFSetGetCount(devSet); CFRelease(devSet); return count; }

If you can use the CFAutorelease() function, that is another way which you could call right after creating it, and it will be collected at the end of the run loop. But using CFRelease directly is a bit more efficient if it doesn't add any complexity to the code. Autoreleasing early can sometimes avoid multiple checks later on if there are multiple returns.

You also need to CFRelease the HIDManager instance, I believe.

Recommend

  • Expected a class or namespace; syntax is proper and correct
  • Replace last values by previous value
  • Counting the rows of a column where the value of a different column is 1
  • counting islands in R csv
  • R using data.table to cut fix time interval that contain 2 or more variables
  • Birt script behaves differently via web viewer
  • In Jquery AND Rails, how to get visible character count of a string?
  • How do I tabulate across an entire R data frame?
  • Density Value for each Return
  • Dimension issue with scipy's curve_fit function
  • How can I convert this tuple of tuples into a count of its elements?
  • What's included in the “Initialization time” in the Symfony2 web profiler?
  • Get highest value from a file using mSL and mIRC
  • How to override JAXB @XMLAccessorType(XMLAccessType.FIELD) specified at a Class level with @XMLEleme
  • Facebook Open Graph Story Custom Actions Keep Getting Rejected - Advice Please?
  • finding symmetric difference/unique elements in multiple arrays in javascript
  • How to enable Drag a Marker (Android Map Api v2) after a single Touch?
  • How do I fix “The program issued a command but the command length is incorrect.” error when calling
  • Error Processing Request: Mage registry key “_singleton/inchoo_notes/feed_updates” already exists
  • Find longest path less than or equal to given value of an acyclic, directed graph in Python
  • How do I bind multiple properties in an Android layout element
  • KnockoutObservableArray with typed elements in TypeScript
  • UWP/C# - Issue with AQS and USB Devices
  • Content-Length header not returned from Pylons response
  • Play WS (2.2.1): post/put large request
  • Atlas images wrong size on iPad iOS 9
  • MongoDB in PHP using aggregate to group by _id is null not working
  • How to access EntityManager inside Entity class in EJB3
  • Is there a javascript serializer for JSON.Net?
  • Projection media query: browser support and workarounds?
  • Why HTML5 Canvas with a larger size stretch a drawn line?
  • Where to put my custom functions in Wordpress?
  • vba code to select only visible cells in specific column except heading
  • WOWZA + RTMP + HTML5 Playback?
  • Buffer size for converting unsigned long to string
  • How to set the response of a form post action to a iframe source?
  • Change div Background jquery
  • Qt: Run a script BEFORE make
  • reshape alternating columns in less time and using less memory
  • Binding checkboxes to object values in AngularJs