How to release memory using vm_deallocate() properly

I am trying to convert the following ObjC code to Swift and found it not as easy due to memory leak.
num_threads_objc() below works fine while num_threads_swift() below seems leaking memory according to Xcode. I suspect the use of vm_deallocate() below is wrong, but can't figure out how.
What am I missing?

int num_threads_objc() {
    thread_act_array_t threads;
    mach_msg_type_number_t thread_count;

    if (task_threads(mach_task_self(), &threads, &thread_count) != KERN_SUCCESS) {
        return -1;
    }
    
    vm_deallocate(mach_task_self(), (vm_address_t)threads, sizeof(thread_t) * thread_count);
    return thread_count;
}
func num_threads_swift() -> Int {
    var threads: thread_act_array_t?
    var thread_count: mach_msg_type_number_t = 0

    guard task_threads(mach_task_self_, &threads, &thread_count) == KERN_SUCCESS else { return -1 }
    
    let size = MemoryLayout<thread_t>.size * Int(thread_count)
    vm_deallocate(mach_task_self_, vm_address_t(threads!.pointee), vm_size_t(size))
    return Int(thread_count)
}

Isn't threads the thing to convert to vm_address_t, not whatever it points to?

Since threads is UnsafeMutablePointer<thread_act_t>?, isn't threads!.pointee the thing to convert and free?

It probably should be

    vm_deallocate(mach_task_self_, vm_address_t(bitPattern: threads!), vm_size_t(size))

(from C array memory deallocation from swift on Stack Overflow).

threads! is the pointer to the memory to be freed (as @jrose said), but vm_deallocate expects the address as an vm_address_t aka UInt. In (Objective-)C you can simply cast the pointer to an
integer. In Swift you need the init(bitPattern:) initializer.

3 Likes

Aww. That was it. Thanks a lot! :)

I have a question,both MemoryLayout<thread_t>.size, MemoryLayout<thread_t>.stride and sizeof(thread_t) have a value of 4, but MemoryLayout.stride and sizeof use memory alignment, so I think using MemoryLayout.stride is more accurate. This is my personal idea, can anyone explain it to me.

so I think using B is more accurate

What is “B” in this context?

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

B means MemoryLayout<thread_t>.stride

So, you mean:

  • MemoryLayout<thread_t>.size is A

  • MemoryLayout<thread_t>.stride is B

  • sizeof(thread_t) is C

?

If so, then yeah, using stride is probably the most correct option. However, in this case thread_t is a UInt32 [1], so it doesn’t matter. Moreover, I don’t think it will ever matter when dealing with basic Mach types like this because they never have any padding.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

[1] Via the chain thread_t > mach_port_t > __darwin_mach_port_t is __darwin_mach_port_name_t > __darwin_natural_t > UInt32, which is quite a chain!

Thanks a lot.