obsidian/笔记文件/2.笔记/ios获取内存相关.md
2025-04-07 15:13:46 +08:00

5.7 KiB
Raw Blame History

#ios #unity/日常积累

ios相关逻辑 头文件:

MemoryInfoPlugin.h

#import <Foundation/Foundation.h>

@interface MemoryInfoPlugin : NSObject

+ (NSString *)getMemoryInfo;
+ (double)getUsedMemoryMB;
+ (double)getTotalMemoryMB;
+ (double)getMemoryUsagePercentage;

@end

MemoryInfoPlugin.mm

#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

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+可用

  • 如果需支持更老版本,需要添加条件编译:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
    return taskInfo.phys_footprint;
#else
    return taskInfo.internal + taskInfo.compressed;
#endif

这个实现方式是目前iOS平台最准确可靠的内存统计方案被主流性能监控工具广泛采用。 也可配合xcode性能检测工具确认性能数据,是否准确