ios 以编程方式检索 iPhone 上的内存使用情况
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/787160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Programmatically retrieve memory usage on iPhone
提问by Coocoo4Cocoa
I'm trying to retrieve the amount of memory my iPhone app is using at anytime, programmatically. Yes I'm aware about ObjectAlloc/Leaks. I'm not interested in those, only to know if it's possible to write some code and get the amount of bytes being used and report it via NSLog.
我正在尝试以编程方式随时检索我的 iPhone 应用程序正在使用的内存量。是的,我知道 ObjectAlloc/Leaks。我对这些不感兴趣,只是想知道是否可以编写一些代码并获取正在使用的字节数并通过 NSLog 报告它。
Thanks.
谢谢。
回答by Jason Coco
To get the actual bytes of memory that your application is using, you can do something like the example below. However, you really should become familiar with the various profiling tools as well as they are designed to give you a much better picture of usage over-all.
要获取您的应用程序正在使用的实际内存字节,您可以执行类似于以下示例的操作。但是,您确实应该熟悉各种分析工具,它们旨在让您更好地了解总体使用情况。
#import <mach/mach.h>
// ...
void report_memory(void) {
struct task_basic_info info;
mach_msg_type_number_t size = TASK_BASIC_INFO_COUNT;
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): %lu", info.resident_size);
NSLog(@"Memory in use (in MiB): %f", ((CGFloat)info.resident_size / 1048576));
} else {
NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
}
}
There is also a field in the structure info.virtual_size which will give you the number of bytes available virtual memory (or memory allocated to your application as potential virtual memory in any event). The code that pgb links to will give you the amount of memory available to the device and what type of memory it is.
结构 info.virtual_size 中还有一个字段,它将为您提供可用虚拟内存的字节数(或在任何情况下作为潜在虚拟内存分配给您的应用程序的内存)。pgb 链接到的代码将为您提供设备可用的内存量以及它是什么类型的内存。
回答by combinatorial
The headers forTASK_BASIC_INFO
say:
标题TASK_BASIC_INFO
说:
/* Don't use this, use MACH_TASK_BASIC_INFO instead */
Here is a version using MACH_TASK_BASIC_INFO
:
这是一个使用的版本MACH_TASK_BASIC_INFO
:
void report_memory(void)
{
struct mach_task_basic_info info;
mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
kern_return_t kerr = task_info(mach_task_self(),
MACH_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));
}
}
回答by Doug Null
Here is report_memory() enhanced to rapidly show leak status in the NSLog().
这是 report_memory() 增强以快速显示 NSLog() 中的泄漏状态。
void report_memory(void) {
static unsigned last_resident_size=0;
static unsigned greatest = 0;
static unsigned last_greatest = 0;
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 ) {
int diff = (int)info.resident_size - (int)last_resident_size;
unsigned latest = info.resident_size;
if( latest > greatest ) greatest = latest; // track greatest mem usage
int greatest_diff = greatest - last_greatest;
int latest_greatest_diff = latest - greatest;
NSLog(@"Mem: %10u (%10d) : %10d : greatest: %10u (%d)", info.resident_size, diff,
latest_greatest_diff,
greatest, greatest_diff );
} else {
NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
}
last_resident_size = info.resident_size;
last_greatest = greatest;
}
回答by Alex Zavatone
This has been tested on Xcode 11 in Mojave 10.4.6 on 07/01/2019.
这已于 2019 年 7 月 1 日在 Mojave 10.4.6 中的 Xcode 11 上进行了测试。
All of the previous answers return the incorrect result.
之前的所有答案都返回错误的结果。
Here is how to get the expected value written by Apple's Quinn “The Eskimo!”.
下面是如何得到苹果的奎因“爱斯基摩人!”所写的期望值。
This uses the phys_footprint
var from Darwin > Mach > task_info
and closely matches the value in the memory gauge in Xcode's Debug navigator.
这使用phys_footprint
var fromDarwin > Mach > task_info
并与 Xcode 的 Debug navigator 中内存量规中的值紧密匹配。
The value returned is in bytes.
返回值以字节为单位。
https://forums.developer.apple.com/thread/105088#357415
https://forums.developer.apple.com/thread/105088#357415
Original code follows.
原始代码如下。
func memoryFootprint() -> mach_vm_size_t? {
// 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 }
return info.phys_footprint
}
Modifying this slightly to create a class level set of Swift methods allows easy return of the actual bytes and formatted output in MB for display. I use this as part of an automated UITest suite to log memory used before and after multiple iterations of the same test to see if we have any potential leaks or allocations we need to look into.
稍微修改它以创建一个类级别的 Swift 方法集,可以轻松返回实际字节和以 MB 为单位的格式化输出以供显示。我使用它作为自动化 UITest 套件的一部分来记录在同一测试的多次迭代之前和之后使用的内存,以查看我们是否有任何需要调查的潜在泄漏或分配。
// Created by Alex Zavatone on 8/1/19.
//
class Memory: NSObject {
// From Quinn the Eskimo at Apple.
// https://forums.developer.apple.com/thread/105088#357415
class 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
}
class func formattedMemoryFootprint() -> String
{
let usedBytes: UInt64? = UInt64(self.memoryFootprint() ?? 0)
let usedMB = Double(usedBytes ?? 0) / 1024 / 1024
let usedMBAsString: String = "\(usedMB)MB"
return usedMBAsString
}
}
Enjoy!
享受!
Note: an enterprising coder may want to add a static formatter to the class so that usedMBAsString
only returns 2 significant decimal places.
注意:有进取心的编码人员可能希望向类添加静态格式化程序,以便usedMBAsString
仅返回 2 个有效小数位。
回答by Nazariy Vlizlo
Swift solution of Jason Coco's answer:
Jason Coco的答案的Swift 解决方案:
func reportMemory() {
let name = mach_task_self_
let flavor = task_flavor_t(TASK_BASIC_INFO)
let basicInfo = task_basic_info()
var size: mach_msg_type_number_t = mach_msg_type_number_t(sizeofValue(basicInfo))
let pointerOfBasicInfo = UnsafeMutablePointer<task_basic_info>.alloc(1)
let kerr: kern_return_t = task_info(name, flavor, UnsafeMutablePointer(pointerOfBasicInfo), &size)
let info = pointerOfBasicInfo.move()
pointerOfBasicInfo.dealloc(1)
if kerr == KERN_SUCCESS {
print("Memory in use (in bytes): \(info.resident_size)")
} else {
print("error with task info(): \(mach_error_string(kerr))")
}
}
回答by BennyTheNerd
Swift 3.1(As of August 8, 2017)
Swift 3.1 (截至 2017 年 8 月 8 日)
func getMemory() {
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) {
func mach_task_self() -> task_t {
return mach_task_self_
}
func getMegabytesUsed() -> Float? {
var info = mach_task_basic_info()
var count = mach_msg_type_number_t(MemoryLayout.size(ofValue: info) / MemoryLayout<integer_t>.size)
let kerr = withUnsafeMutablePointer(to: &info) { infoPtr in
return infoPtr.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { (machPtr: UnsafeMutablePointer<integer_t>) in
return task_info(
mach_task_self(),
task_flavor_t(MACH_TASK_BASIC_INFO),
machPtr,
&count
)
}
}
guard kerr == KERN_SUCCESS else {
return nil
}
return Float(info.resident_size) / (1024 * 1024)
}
.withMemoryRebound(to: integer_t.self, capacity: 1) {
task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), size_t memoryFootprint()
{
task_vm_info_data_t vmInfo;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
if (result != KERN_SUCCESS)
return 0;
return static_cast<size_t>(vmInfo.phys_footprint);
}
, &count)
}
}
if kerr == KERN_SUCCESS {
let usedMegabytes = taskInfo.resident_size/(1024*1024)
print("used megabytes: \(usedMegabytes)")
} else {
print("Error with task_info(): " +
(String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error"))
}
}
回答by jeffbailey
Here's a Swift 3 Version:
这是一个 Swift 3 版本:
float GetTotalPhysicsMemory()
{
struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kr;
kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
if (kr == KERN_SUCCESS)
return (float)(info.resident_size) / 1024.0 / 1024.0;
else
return 0;
}
回答by Jimmy Yin
回答by rensq
Below is the correct answer:
下面是正确答案:
```
``
##代码##```
``