14

How to get memory usage of my application and system in swift by programatically?

not only system, but also my application

SubCycle
  • 463
  • 2
  • 6
  • 16

3 Answers3

21

For Swift 3.0 you can use the following function.

func report_memory() {
    var taskInfo = mach_task_basic_info()
    var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size)/4
    let kerr: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) {
        $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
            task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count)
        }
    }

    if kerr == KERN_SUCCESS {
        print("Memory used in bytes: \(taskInfo.resident_size)")
    }
    else {
        print("Error with task_info(): " +
            (String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error"))
    }
}
dirtydanee
  • 6,081
  • 2
  • 27
  • 43
  • thx, by the way,where can i find the documentation of the apple's Darwin api, such as `mach_task_basic_info ` `kern_return_t ` – SubCycle Dec 08 '16 at 12:22
  • well there is this, https://opensource.apple.com/source/xnu/xnu-2050.9.2/osfmk/mach/task_info.h , but i am not sure if there is anything else Apple specific documentation. – dirtydanee Dec 08 '16 at 12:29
  • 3
    The code works, but the value get by the code is different with other App(BMSSM/sys Status/etc). Dont know which one is correct. – DàChún Oct 06 '17 at 14:23
  • Values are not matched with what is shown by xcode's debugger. This function shows 36 mb where as in xcode it is 12 mb – user1101733 Mar 14 '18 at 19:04
  • 1
    The memory usage using this code shows x3 times the memory usage from the debugger. Why? –  Apr 23 '18 at 09:20
  • 1
    this answer gives a wrong result. check the one below by mAc, it works correctly – Gasper J. Jan 13 '21 at 14:28
  • This is not a correct answer, please look below for my perfect answer. Upvote if it helps you :) – mAc Mar 24 '21 at 09:51
14

Found and tested this on XCode 12.2 and Mac OS Catalina 10.15.6 and it works like charm:

func memoryFootprint() -> Float? {
    // The `TASK_VM_INFO_COUNT` and `TASK_VM_INFO_REV1_COUNT` macros are too
    // complex for the Swift C importer, so we have to define them ourselves.
    let TASK_VM_INFO_COUNT = mach_msg_type_number_t(MemoryLayout<task_vm_info_data_t>.size / MemoryLayout<integer_t>.size)
    let TASK_VM_INFO_REV1_COUNT = mach_msg_type_number_t(MemoryLayout.offset(of: \task_vm_info_data_t.min_address)! / MemoryLayout<integer_t>.size)
    var info = task_vm_info_data_t()
    var count = TASK_VM_INFO_COUNT
    let kr = withUnsafeMutablePointer(to: &info) { infoPtr in
        infoPtr.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { intPtr in
            task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), intPtr, &count)
        }
    }
    guard
        kr == KERN_SUCCESS,
        count >= TASK_VM_INFO_REV1_COUNT
    else { return nil }
    
    let usedBytes = Float(info.phys_footprint)
    return usedBytes
    
}

func formattedMemoryFootprint() -> String {
    let usedBytes: UInt64? = UInt64(self.memoryFootprint() ?? 0)
    let usedMB = Double(usedBytes ?? 0) / 1024 / 1024
    let usedMBAsString: String = "Memory Used by App: \(usedMB)MB"
    return usedMBAsString
}

Hope this helps someone too :)

mAc
  • 2,434
  • 2
  • 22
  • 39
6

mAc's answers but without force unwrapping:

func memoryFootprint() -> String {
    // The `TASK_VM_INFO_COUNT` and `TASK_VM_INFO_REV1_COUNT` macros are too
    // complex for the Swift C importer, so we have to define them ourselves.
    let TASK_VM_INFO_COUNT = mach_msg_type_number_t(MemoryLayout<task_vm_info_data_t>.size / MemoryLayout<integer_t>.size)
    guard let offset = MemoryLayout.offset(of: \task_vm_info_data_t.min_address) else {return "memory: NA"}
    let TASK_VM_INFO_REV1_COUNT = mach_msg_type_number_t(offset / MemoryLayout<integer_t>.size)
    var info = task_vm_info_data_t()
    var count = TASK_VM_INFO_COUNT
    let kr = withUnsafeMutablePointer(to: &info) { infoPtr in
        infoPtr.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { intPtr in
            task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), intPtr, &count)
        }
    }
    guard
        kr == KERN_SUCCESS,
        count >= TASK_VM_INFO_REV1_COUNT
    else { return "memory: NA" }
    
    let usedBytes = Float(info.phys_footprint)
    let usedBytesInt: UInt64 = UInt64(usedBytes)
    let usedMB = usedBytesInt / 1024 / 1024
    let usedMBAsString: String = "memory: \(usedMB) MB"
    return usedMBAsString
}