Swift pointer problems with MACH_TASK_BASIC_INFO

后端 未结 6 2094
一个人的身影
一个人的身影 2020-12-08 08:58

I am trying to convert an ObjC stackoverflow answer to Swift and failing. It looks like I am passing a UnsafeMutablePointer when I

相关标签:
6条回答
  • 2020-12-08 09:24

    Airspeed Velocity's answer in Swift 3...

    func GetMemory()
    {
        var info = mach_task_basic_info()
        var count = mach_msg_type_number_t(MemoryLayout.size(ofValue: info))/4
    
        let kerr: kern_return_t = withUnsafeMutablePointer(to: &info)
        {
    
            task_info(mach_task_self_,
                      task_flavor_t(MACH_TASK_BASIC_INFO),
                      $0.withMemoryRebound(to: Int32.self, capacity: 1) { zeroPtr in
                        task_info_t(zeroPtr)
                      },
                      &count)
    
        }
    
        if kerr == KERN_SUCCESS {
            print("Memory in use (in bytes): \(info.resident_size)")
        }
        else {
            print("Error with task_info(): " +
                (String.init(validatingUTF8: mach_error_string(kerr)) ?? "unknown error"))
        }
    }
    
    0 讨论(0)
  • 2020-12-08 09:26

    Took me a bit to update Airspeed Velocity's answer to the latest swift syntax (Swift 3, beta 6), but here is what I got:

    func report_memory() {
        var info = mach_task_basic_info()
        let MACH_TASK_BASIC_INFO_COUNT = MemoryLayout<mach_task_basic_info>.stride/MemoryLayout<natural_t>.stride
        var count = mach_msg_type_number_t(MACH_TASK_BASIC_INFO_COUNT)
    
        let kerr: kern_return_t = withUnsafeMutablePointer(to: &info) {
            $0.withMemoryRebound(to: integer_t.self, capacity: MACH_TASK_BASIC_INFO_COUNT) {
                task_info(mach_task_self_,
                          task_flavor_t(MACH_TASK_BASIC_INFO),
                          $0,
                          &count)
            }
        }
    
        if kerr == KERN_SUCCESS {
            print("Memory in use (in bytes): \(info.resident_size)")
        }
        else {
            print("Error with task_info(): " +
                (String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error"))
        }
    }
    

    Hope that's helpful.

    0 讨论(0)
  • 2020-12-08 09:28

    Nate’s answer is excellent but there’s a tweak you can make to simplify it.

    First, rather than allocating/deallocating the task_basic_info pointer, you can create the struct on the stack, then use withUnsafeMutablePointer to get a pointer directly to it which you can pass in.

    func report_memory() {
        var info = mach_task_basic_info()
        var count = mach_msg_type_number_t(sizeofValue(info))/4
    
        let kerr: kern_return_t = withUnsafeMutablePointer(&info) {
    
            task_info(mach_task_self_,
                task_flavor_t(MACH_TASK_BASIC_INFO),
                task_info_t($0),
                &count)
    
        }
    
        if kerr == KERN_SUCCESS {
            println("Memory in use (in bytes): \(info.resident_size)")
        }
        else {
            println("Error with task_info(): " +
                (String.fromCString(mach_error_string(kerr)) ?? "unknown error"))
        }
    }
    
    0 讨论(0)
  • 2020-12-08 09:30

    Swift 5 + Combine, Continuous memory Monitoring

    Show exact memory in MB like XCODE

    import Foundation
    import Combine
    
     enum MemoryMonitorState {
        case started
        case paused
    }
    
    
    class MemoryUsageCustom {
        
        private var displayLink: CADisplayLink!
    
        var state = MemoryMonitorState.paused
        
        let subject = PassthroughSubject<String, Never>()
    
        
        private static var sharedInstance: MemoryUsageCustom!
        
        public class func shared() -> MemoryUsageCustom {
            if self.sharedInstance == nil {
                self.sharedInstance = MemoryUsageCustom()
            }
            return self.sharedInstance
        }
        
        private init() {
            self.configureDisplayLink()
    
        }
        
        func startMemoryMonitor() {
            
            if self.state == .started {
                return
            }
            
            self.state = .started
            self.start()
        }
        
        func stopMemoryMonitor() {
            self.state = .paused
            self.pause()
        }
        
    
        //--------------------------------------------------------------------------------
        
        //MARK:- Display Link
        
        //--------------------------------------------------------------------------------
    
     
        func configureDisplayLink() {
            self.displayLink = CADisplayLink(target: self, selector: #selector(displayLinkAction(displayLink:)))
            self.displayLink.isPaused = true
            self.displayLink?.add(to: .current, forMode: .common)
        }
        
        private func start() {
            self.displayLink?.isPaused = false
        }
        
        /// Pauses performance monitoring.
        private func pause() {
            self.displayLink?.isPaused = true
        }
        
        @objc func displayLinkAction(displayLink: CADisplayLink) {
            let memoryUsage = self.memoryUsage()
            
            let bytesInMegabyte = 1024.0 * 1024.0
            let usedMemory = Double(memoryUsage.used) / bytesInMegabyte
            let totalMemory = Double(memoryUsage.total) / bytesInMegabyte
            let memory = String(format: "%.1f of %.0f MB used", usedMemory, totalMemory)
    
         //   self.memoryString = memory
            subject.send(memory)
        }
        
        func memoryUsage() -> (used: UInt64, total: UInt64) {
            var taskInfo = task_vm_info_data_t()
            var count = mach_msg_type_number_t(MemoryLayout<task_vm_info>.size) / 4
            let result: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) {
                $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
                    task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), $0, &count)
                }
            }
            
            var used: UInt64 = 0
            if result == KERN_SUCCESS {
                used = UInt64(taskInfo.phys_footprint)
            }
            
            let total = ProcessInfo.processInfo.physicalMemory
            return (used, total)
        }
    
    }
    

    How To use


       //Start Monitoring 
        MemoryUsageCustom.shared().startMemoryMonitor()
    
    var storage = Set<AnyCancellable>()
    
        MemoryUsageCustom.shared().subject.sink {[weak self] (string) in
            print(string)
    
        }.store(in: &storage)
    
    0 讨论(0)
  • 2020-12-08 09:31

    When interacting with C functions, you can't rely on the compiler's error messages - break it down parameter by parameter, command-clicking until you know what you're working with. To start with, the types you're running into are:

    • task_name_t: UInt32
    • task_flavor_t: UInt32
    • task_info_t: UnsafeMutablePointer<Int32>
    • UnsafeMutablePointer<mach_msg_type_number_t>: UnsafeMutablePointer<UInt32>
    • kern_return_t - Int32

    There's one tricky Swift bit along with a bug in your code standing in your way here. First, the task_info_out parameter needs to be a UnsafeMutablePointer<UInt32>, but needs to actually point to an instance of mach_task_basic_info. We can get around this by creating a UnsafeMutablePointer<mach_task_basic_info> and wrapping it in another UnsafeMutablePointer at call time - the compiler will use type inference to know we want that wrapping pointer to be sub-typed as UInt32.

    Second, you're calling sizeof(mach_task_basic_info_t) (the pointer to mach_task_basic_info) when you should be calling sizeinfo(mach_task_basic_info), so your byte count ends up too low to hold the data structure.

    On further research, this got a little more complicated. The original code for this was incorrect, in that size should be initialized to the constant MACH_TASK_BASIC_INFO_COUNT. Unfortunately, that's a macro, not a simple constant:

    #define MACH_TASK_BASIC_INFO_COUNT (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t)) 
    

    Swift doesn't import those, so we'll need to redefine it ourselves. Here's working code for all this:

    // constant
    let MACH_TASK_BASIC_INFO_COUNT = (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))
    
    // prepare parameters
    let name   = mach_task_self_
    let flavor = task_flavor_t(MACH_TASK_BASIC_INFO)
    var size   = mach_msg_type_number_t(MACH_TASK_BASIC_INFO_COUNT)
    
    // allocate pointer to mach_task_basic_info
    var infoPointer = UnsafeMutablePointer<mach_task_basic_info>.alloc(1)
    
    // call task_info - note extra UnsafeMutablePointer(...) call
    let kerr = task_info(name, flavor, UnsafeMutablePointer(infoPointer), &size)
    
    // get mach_task_basic_info struct out of pointer
    let info = infoPointer.move()
    
    // deallocate pointer
    infoPointer.dealloc(1)
    
    // check return value for success / failure
    if kerr == KERN_SUCCESS {
        println("Memory in use (in bytes): \(info.resident_size)")
    } else {
        let errorString = String(CString: mach_error_string(kerr), encoding: NSASCIIStringEncoding)
        println(errorString ?? "Error: couldn't parse error string")
    }
    
    0 讨论(0)
  • 2020-12-08 09:34

    For a quick copy and paste solution in Swift 5, use

    func reportMemory() {
        var taskInfo = task_vm_info_data_t()
        var count = mach_msg_type_number_t(MemoryLayout<task_vm_info>.size) / 4
        let result: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) {
            $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
                task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), $0, &count)
            }
        }
        let usedMb = Float(taskInfo.phys_footprint) / 1048576.0
        let totalMb = Float(ProcessInfo.processInfo.physicalMemory) / 1048576.0
        result != KERN_SUCCESS ? print("Memory used: ? of \(totalMb)") : print("Memory used: \(usedMb) of \(totalMb)")
    }
    
    0 讨论(0)
自定义标题
段落格式
字体
字号
代码语言
提交回复
热议问题