如何在Swift中获取内存使用情况

20

我需要以编程方式在Swift中获取我的应用程序的内存使用情况(MB)。我找到了Objective-C的示例代码。有人可以帮我将其转换为Swift吗?谢谢!

void report_memory(void) {
  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);
  if( kerr == KERN_SUCCESS ) {
    NSLog(@"Memory in use (in bytes): %u", info.resident_size);
  } else {
    NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
  }
}
2个回答

13

编辑:糟糕,应该先检查重复,Nate已经在这里回答了这个问题。不过你可能想注意一下我的版本中略微的不同之处,它使用了withUnsafeMutablePointer

人们不喜欢“如何将这个Obj-C代码转换为Swift”的问题,所以你得到了负分。但是,在这种情况下,这可能是公平的,因为这个具体的转换特别棘手。我认为这个代码可以工作:

func report_memory() {
    var info = 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(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"))
    }
}

有几种基本的强制转换——sizeof返回一个Int,但函数调用需要一个UInt32。同样(稍微更加令人恼火的是),TASK_BASIC_INFO是一个Int32,但调用需要一个UInt32

麻烦的部分在于传递第三个参数。task_info需要一个指向多种不同大小的结构体的指针,具体取决于你想要的信息类型。因此,你需要从你的task_basic_info对象获取一个指针,然后将其转换为task_info实际想要的特定指针类型(一旦你穿过所有的typedef,它是一个指向UInt32的指针)。

task_info的文档说,最后一个count参数应该是“task_info中整数的最大数量”,但是当它说整数时,我想它是指32位整数,因此除以4。


嘿!你解决了吗?如何在应用程序开始发送内存警告之前找到限制?换句话说,我如何知道何时正在“推动”应用程序的内存使用情况,并停止进行任何正在进行的进程? - Roi Mulia
在Swift 3中,我现在得到了“'init'不可用:使用'withMemoryRebound(to:capacity:_)'将内存暂时视为另一种布局兼容类型。” - Mason G. Zhwiti
1
Swift 3 解决方案:https://dev59.com/Il4c5IYBdhLWcg3wv8pm#39048651 - Mason G. Zhwiti
这是应用程序(进程)的内存使用情况,而不是设备的。 - Shrikant Phadke
1
过时了。在Swift 5中会产生一堆编译器错误。 - Xander Dunn

1

终于我找到了一个解决方案。请看下面的代码片段。

func report_memory() {
    // 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 MB): \(info.resident_size/1000000)")
    } else {
        let errorString = String(CString: mach_error_string(kerr), encoding: NSASCIIStringEncoding)
        println(errorString ?? "Error: couldn't parse error string")
    }    
}

4
抄袭别人的答案并不等同于“找到了解决方案”。至少要给最先发布答案的人以功劳:https://dev59.com/Il4c5IYBdhLWcg3wv8pm#27559770 - timbre timbre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接