MACH_TASK_BASIC_INFO的Swift指针问题

tob*_*fin 9 mach swift

我试图将ObjC stackoverflow答案转换为Swift并失败.看起来我正在通过一个UnsafeMutablePointer<mach_msg_type_number_t>我应该通过的时候inout mach_msg_type_number_t,我似乎无法解决我的问题.根据我对Swift指针文档的理解(不多),这些应该是可以互换的.

更多信息如下.

这是目标C:

struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
Run Code Online (Sandbox Code Playgroud)

就我在Swift中所获得的而言(许多行更容易进行类型检查)

let name: task_name_t = mach_task_self_
let flavor: task_flavor_t = task_flavor_t(MACH_TASK_BASIC_INFO)
var info: mach_task_basic_info
var size: mach_msg_type_number_t = UnsignedFixed(sizeof(mach_task_basic_info_t))
let kerr = task_info(name, flavor, info as task_info_t, &size)
Run Code Online (Sandbox Code Playgroud)

task_info签名是:

func task_info(target_task: task_name_t, flavor: task_flavor_t, task_info_out: task_info_t, task_info_outCnt: UnsafeMutablePointer<mach_msg_type_number_t>) -> kern_return_t
Run Code Online (Sandbox Code Playgroud)

并且最后一行的错误是:

Cannot convert the expression's type '(@!lvalue task_name_t, task_flavor_t, task_info_t, inout mach_msg_type_number_t)' to type 'kern_return_t'
Run Code Online (Sandbox Code Playgroud)

Jer*_*rry 31

我有点更新了Airspeed Velocity对最新swift语法(Swift 3,beta 6)的回答,但这是我得到的:

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"))
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这很有帮助.

  • 你能帮我理解这个值与调试器显示的内存值的比较吗?我目前正在获得106mb的resident_size,但xcode告诉我我正在使用34mb与其他使用1gb和1gb免费的进程. (5认同)

Nat*_*ook 12

与C函数交互时,您不能依赖编译器的错误消息 - 按参数分解参数,按住命令单击,直到您知道正在使用的内容为止.首先,您遇到的类型是:

  • 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

有一个棘手的Swift位以及你的代码中存在的错误.首先,task_info_out参数需要是a UnsafeMutablePointer<UInt32>,但实际上需要指向一个实例mach_task_basic_info.我们可以通过在调用时创建一个UnsafeMutablePointer<mach_task_basic_info>并将其包装在另一个 UnsafeMutablePointer中来解决这个问题- 编译器将使用类型推断来知道我们希望包装指针被子类型化为UInt32.

其次,当你应该调用时,你正在调用sizeof(mach_task_basic_info_t)(指向mach_task_basic_info)sizeinfo(mach_task_basic_info),因此你的字节数太低而无法容纳数据结构.

在进一步的研究中,这有点复杂.原始代码不正确,size应该初始化为常量MACH_TASK_BASIC_INFO_COUNT.不幸的是,这是一个宏,而不是一个简单的常量:

#define MACH_TASK_BASIC_INFO_COUNT (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t)) 
Run Code Online (Sandbox Code Playgroud)

Swift不会导入它们,所以我们需要自己重新定义它们.这是所有这些的工作代码:

// 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")
}
Run Code Online (Sandbox Code Playgroud)


Air*_*ity 9

Nate的答案非常好,但您可以通过调整来简化它.

首先,task_basic_info您可以在堆栈上创建结构,而不是分配/取消分配指针,然后使用withUnsafeMutablePointer直接获取指针,您可以传入该指针.

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"))
    }
}
Run Code Online (Sandbox Code Playgroud)


Pra*_*iya 7

Swift 5 + 组合,连续内存监控

像 XCODE 一样以 MB 为单位显示确切的内存

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)
    }

}
Run Code Online (Sandbox Code Playgroud)

如何使用


   //Start Monitoring 
    MemoryUsageCustom.shared().startMemoryMonitor()

var storage = Set<AnyCancellable>()

    MemoryUsageCustom.shared().subject.sink {[weak self] (string) in
        print(string)

    }.store(in: &storage)
Run Code Online (Sandbox Code Playgroud)


小智 5

Airspeed Velocity 在 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"))
    }
}
Run Code Online (Sandbox Code Playgroud)


Pix*_*xel 5

要在 Swift 5 中快速复制和粘贴解决方案,请使用

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)")
}
Run Code Online (Sandbox Code Playgroud)