2025-03-26 17:54:55 +08:00
|
|
|
|
#ios
|
|
|
|
|
|
#unity/日常积累
|
|
|
|
|
|
|
|
|
|
|
|
ios相关逻辑
|
|
|
|
|
|
头文件:
|
|
|
|
|
|
|
|
|
|
|
|
## MemoryInfoPlugin.h
|
|
|
|
|
|
|
2025-04-07 15:13:46 +08:00
|
|
|
|
``` objc
|
2025-03-26 17:54:55 +08:00
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
|
|
|
|
|
|
|
|
@interface MemoryInfoPlugin : NSObject
|
|
|
|
|
|
|
|
|
|
|
|
+ (NSString *)getMemoryInfo;
|
|
|
|
|
|
+ (double)getUsedMemoryMB;
|
|
|
|
|
|
+ (double)getTotalMemoryMB;
|
|
|
|
|
|
+ (double)getMemoryUsagePercentage;
|
|
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## MemoryInfoPlugin.mm
|
|
|
|
|
|
|
2025-04-07 15:13:46 +08:00
|
|
|
|
``` objc
|
2025-03-26 17:54:55 +08:00
|
|
|
|
#import "MemoryInfoPlugin.h"
|
|
|
|
|
|
#import <mach/mach.h>
|
|
|
|
|
|
#import <sys/sysctl.h>
|
|
|
|
|
|
|
|
|
|
|
|
@implementation MemoryInfoPlugin
|
|
|
|
|
|
|
|
|
|
|
|
+ (NSString *)getMemoryInfo {
|
|
|
|
|
|
double used = [self getUsedMemoryMB];
|
|
|
|
|
|
double total = [self getTotalMemoryMB];
|
|
|
|
|
|
double percentage = [self getMemoryUsagePercentage];
|
|
|
|
|
|
|
|
|
|
|
|
return [NSString stringWithFormat:@"已使用: %.2f MB, 总共: %.2f MB, 使用率: %.2f%%",
|
|
|
|
|
|
used, total, percentage];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+ (double)getUsedMemoryMB {
|
|
|
|
|
|
task_vm_info_data_t taskInfo;
|
|
|
|
|
|
mach_msg_type_number_t infoCount = TASK_VM_INFO_COUNT;
|
|
|
|
|
|
kern_return_t kernReturn = task_info(mach_task_self(),
|
|
|
|
|
|
TASK_VM_INFO,
|
|
|
|
|
|
(task_info_t)&taskInfo,
|
|
|
|
|
|
&infoCount);
|
|
|
|
|
|
|
|
|
|
|
|
if (kernReturn != KERN_SUCCESS) {
|
|
|
|
|
|
return -1.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (double)taskInfo.phys_footprint / 1024.0 / 1024.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+ (double)getTotalMemoryMB {
|
|
|
|
|
|
int64_t memorySize = 0;
|
|
|
|
|
|
size_t size = sizeof(memorySize);
|
|
|
|
|
|
sysctlbyname("hw.memsize", &memorySize, &size, NULL, 0);
|
|
|
|
|
|
|
|
|
|
|
|
return (double)memorySize / 1024.0 / 1024.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+ (double)getMemoryUsagePercentage {
|
|
|
|
|
|
double used = [self getUsedMemoryMB];
|
|
|
|
|
|
double total = [self getTotalMemoryMB];
|
|
|
|
|
|
|
|
|
|
|
|
if (total > 0) {
|
|
|
|
|
|
return (used / total) * 100.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return -1.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 为Unity导出C函数
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
const char* _GetMemoryInfo() {
|
|
|
|
|
|
NSString *info = [MemoryInfoPlugin getMemoryInfo];
|
|
|
|
|
|
return strdup([info UTF8String]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double _GetUsedMemoryMB() {
|
|
|
|
|
|
return [MemoryInfoPlugin getUsedMemoryMB];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double _GetTotalMemoryMB() {
|
|
|
|
|
|
return [MemoryInfoPlugin getTotalMemoryMB];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double _GetMemoryUsagePercentage() {
|
|
|
|
|
|
return [MemoryInfoPlugin getMemoryUsagePercentage];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
调用 测试用例
|
|
|
|
|
|
## IOSMemoryInfo.cs
|
|
|
|
|
|
|
|
|
|
|
|
``` cs
|
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
public class IOSMemoryInfo : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
#if UNITY_IOS && !UNITY_EDITOR
|
|
|
|
|
|
[DllImport("__Internal")]
|
|
|
|
|
|
private static extern string _GetMemoryInfo();
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport("__Internal")]
|
|
|
|
|
|
private static extern double _GetUsedMemoryMB();
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport("__Internal")]
|
|
|
|
|
|
private static extern double _GetTotalMemoryMB();
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport("__Internal")]
|
|
|
|
|
|
private static extern double _GetMemoryUsagePercentage();
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// 获取完整内存信息字符串
|
|
|
|
|
|
public static string GetMemoryInfo()
|
|
|
|
|
|
{
|
|
|
|
|
|
#if UNITY_IOS && !UNITY_EDITOR
|
|
|
|
|
|
return _GetMemoryInfo();
|
|
|
|
|
|
#else
|
|
|
|
|
|
return "仅支持iOS设备";
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取已使用内存(MB)
|
|
|
|
|
|
public static double GetUsedMemoryMB()
|
|
|
|
|
|
{
|
|
|
|
|
|
#if UNITY_IOS && !UNITY_EDITOR
|
|
|
|
|
|
return _GetUsedMemoryMB();
|
|
|
|
|
|
#else
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取总内存(MB)
|
|
|
|
|
|
public static double GetTotalMemoryMB()
|
|
|
|
|
|
{
|
|
|
|
|
|
#if UNITY_IOS && !UNITY_EDITOR
|
|
|
|
|
|
return _GetTotalMemoryMB();
|
|
|
|
|
|
#else
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取内存使用百分比
|
|
|
|
|
|
public static double GetMemoryUsagePercentage()
|
|
|
|
|
|
{
|
|
|
|
|
|
#if UNITY_IOS && !UNITY_EDITOR
|
|
|
|
|
|
return _GetMemoryUsagePercentage();
|
|
|
|
|
|
#else
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用示例
|
|
|
|
|
|
void Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
InvokeRepeating("ShowMemoryInfo", 1.0f, 5.0f);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ShowMemoryInfo()
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("内存信息: " + GetMemoryInfo());
|
|
|
|
|
|
Debug.Log("已使用: " + GetUsedMemoryMB() + " MB");
|
|
|
|
|
|
Debug.Log("总内存: " + GetTotalMemoryMB() + " MB");
|
|
|
|
|
|
Debug.Log("使用率: " + GetMemoryUsagePercentage() + "%");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
相关目录结构:
|
|
|
|
|
|
|
|
|
|
|
|
![[Pasted image 20250326153420.png]]
|
|
|
|
|
|
|
|
|
|
|
|
![[Pasted image 20250326153443.png]]
|
|
|
|
|
|
|
|
|
|
|
|
最终xcode运行效果:
|
|
|
|
|
|
|
|
|
|
|
|
![[Pasted image 20250326153542.png]]
|
|
|
|
|
|
|
|
|
|
|
|
## 相关逻辑解析
|
|
|
|
|
|
|
|
|
|
|
|
这个获取iOS内存占用的方法有效,主要基于以下几个关键点:
|
|
|
|
|
|
|
|
|
|
|
|
1. Mach API的使用:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
task_info(mach_task_self(), TASK_VM_INFO, ...)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
这是iOS/macOS底层Mach内核提供的API,可以直接访问进程的内存信息。Mach是XNU内核的核心组件,专门负责内存管理等基础服务。
|
|
|
|
|
|
|
|
|
|
|
|
2. phys_footprint字段:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
taskInfo.phys_footprint
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
这是Apple在iOS 9+引入的专用字段,表示:
|
|
|
|
|
|
|
|
|
|
|
|
- 实际物理内存使用量(非虚拟内存)
|
|
|
|
|
|
|
|
|
|
|
|
- 包含压缩内存(Compressed Memory)
|
|
|
|
|
|
|
|
|
|
|
|
- 包含IOKit使用的内存
|
|
|
|
|
|
|
|
|
|
|
|
- 符合Xcode Memory Report的统计标准
|
|
|
|
|
|
|
|
|
|
|
|
3. 与系统监控的一致性:
|
|
|
|
|
|
|
|
|
|
|
|
这个数值与Xcode Debug Gauges显示的内存值完全一致,是Apple官方推荐的内存统计方式。相比过时的resident_size字段,phys_footprint能更准确地反映真实内存使用情况。
|
|
|
|
|
|
|
|
|
|
|
|
4. 权限处理:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
mach_task_self()
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
通过获取当前进程的task端口,避免了越权访问的问题,符合iOS的沙盒安全机制。
|
|
|
|
|
|
|
|
|
|
|
|
5. 单位转换:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
/ 1024.0 / 1024.0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
将字节转换为MB的经典处理方式(1MB = 1024KB = 10241024B)
|
|
|
|
|
|
|
|
|
|
|
|
需要注意的版本适配:
|
|
|
|
|
|
|
|
|
|
|
|
- phys_footprint在iOS 9.0+可用
|
|
|
|
|
|
|
|
|
|
|
|
- 如果需支持更老版本,需要添加条件编译:
|
|
|
|
|
|
|
|
|
|
|
|
``` cpp
|
|
|
|
|
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
|
|
|
|
|
|
return taskInfo.phys_footprint;
|
|
|
|
|
|
#else
|
|
|
|
|
|
return taskInfo.internal + taskInfo.compressed;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
这个实现方式是目前iOS平台最准确可靠的内存统计方案,被主流性能监控工具广泛采用。
|
|
|
|
|
|
也可配合[[xcode性能检测工具]]确认性能数据,是否准确
|