在使用GPU将训练出来的模型运行iOS时,发现对于稍微大一点的图片,内存会存在暴增问题。严重时出现了闪退。因此需要监控SDK在工作时的内存实时消耗情况。在使用iOS监控资源时,查询相关资料,不过大都是OC版本的,其实有涉及到很多C语言方面的语法转换,在转换的时候遇到了不少问题,如提示:Cannot convert value of type 'mach_task_basic_info' to type 'integer_t' (aka 'Int32') in coercion。查询了很多资料并结合此篇文章,给出swift版本:
代码:
func report_memory()->ApplicationMemoryCurrentUsage {
var info = 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: &info) {
$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 in use (in bytes): \(info.resident_size)")
let usage = info.resident_size / (1024 * 1024)
let total = ProcessInfo.processInfo.physicalMemory / (1024 * 1024)
let ratio = Double(info.virtual_size) / Double(ProcessInfo.processInfo.physicalMemory)
return ApplicationMemoryCurrentUsage(usage: Double(usage), total: Double(total), ratio: Double(ratio))
}
else {
print("Error with task_info(): " +
(String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error"))
return ApplicationMemoryCurrentUsage()
}
其中的ApplicationMemoryCurrentUsage是一个结构体,其结构体内部分别代表着已用内存,总内存,和占用比例。而1024*1024是从MB->KB->B的转换,结构体具体为:
struct ApplicationMemoryCurrentUsage{
var usage : Double = 0.0
var total : Double = 0.0
var ratio : Double = 0.0
}
本以为以上的代码会解决实际问题,但是最终运行并对比Xcode自带的memory检测工具来看,差别太大。特别是最后发现ratio有时候会大于1,最终检查发现,给出的内存数据是虚拟数据,这代表不了实际的物理内存。具体的iOS内存分配问题感觉此篇文章解释的还算不错。
那么如何给出物理内存的使用情况的,通过查找文章发现:vm_statistice_data_t()函数控制着整体系统上物理内存信息。最终代码如下,ApplicationMemoryCurrentUsage结构体我稍作了一下改动。
func getUsedMemory()->ApplicationMemoryCurrentUsage {
var applicationUseageMemory = ApplicationMemoryCurrentUsage.init()
var usedMemory: Int64 = 0
let hostPort: mach_port_t = mach_host_self()
var host_size: mach_msg_type_number_t = mach_msg_type_number_t(MemoryLayout<vm_statistics_data_t>.stride / MemoryLayout<integer_t>.stride)
var pagesize:vm_size_t = 0
host_page_size(hostPort, &pagesize)
var vmStat: vm_statistics = vm_statistics_data_t()
let status: kern_return_t = withUnsafeMutableBytes(of: &vmStat) {
let boundPtr = $0.baseAddress?.bindMemory(to: Int32.self, capacity: MemoryLayout.size(ofValue: vmStat) / MemoryLayout<Int32>.stride)
return host_statistics(hostPort, HOST_VM_INFO, boundPtr, &host_size)
}
if status == KERN_SUCCESS {
usedMemory = (Int64)((vm_size_t)(vmStat.active_count + vmStat.inactive_count + vmStat.wire_count) * pagesize)
let total = (Int64)(ProcessInfo.processInfo.physicalMemory)
applicationUseageMemory.usageMemory = usedMemory
applicationUseageMemory.freeMemory = (Int64)(total) - usedMemory
applicationUseageMemory.usedRatio = (Double)(usedMemory) / (Double)(total)
return applicationUseageMemory
}
else {
print("Failed to get Virtual memory inforor")
return applicationUseageMemory
}
}
通过运行并对比Xcode自带的内存检测工具发现,数据相差很少。由于对iOS的内存分配掌握的还不够充足,有一些问题还有待解决,比如说kern_reture_t有个free_count属性,但是通过(Int64)(total) - usedMemory 语句计算出来的值和直接通过free_return_t.free_count得到的相差300M左右的数据。欢迎各位大神补充相关方面的知识。