1

我有一个问题:如果我尝试使用Texture2D.ReadPixels创建屏幕截图,游戏会在某些设备(尤其是 iPod 4G)上崩溃。据推测,它是因为内存不足而发生的。在创建屏幕截图之前,我想检测是否可以安全地分配所需的内存量,并在我认为我会崩溃时向播放器显示警告。

然而,像纹理这样的资源似乎是在 Mono VM 之外进行管理的。System.GC.GetTotalMemory 返回 9mb,当我有 16mb 大的图集时。所以,看来我必须为此编写一个插件。

(有一段描述我没有收到内存不足的警告,但似乎我弄错了,在Objective-C级别上,警告成功提出了)。

如何在不崩溃的情况下获得可以分配的“空闲”内存量?可能还有其他方法可以实现我想要的功能吗?

4

3 回答 3

6

解释你自己的答案:这不是 Objective-C 代码,而是普通的旧 C,使用 Mach API 来从内核获取统计信息。Mach API 是由 XNU 导出的低级 API,它是一个混合内核,由顶层(导出 BSD API,就像我们从 UN*X 熟悉和喜爱的常用系统调用一样)和底层(即 Mach)组成。该代码使用马赫“主机”抽象,它(除其他外)提供有关操作系统级别资源利用率的统计信息。

具体来说,这是一个完整的注释:

#import <mach/mach.h>       // Required for generic Mach typedefs, like the mach_port_t
#import <mach/mach_host.h>  // Required for the host abstraction APIs.

extern "C" // C, rather than objective-c
{

    const int HWUtils_getFreeMemory()
    {
        mach_port_t host_port;             
        mach_msg_type_number_t host_size;
        vm_size_t pagesize;

        // First, get a reference to the host port. Any task can do that, and this
        // requires no privileges
        host_port = mach_host_self();
        host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);

        // Get host page size - usually 4K
        host_page_size(host_port, &pagesize);

        vm_statistics_data_t vm_stat;

        // Call host_statistics, requesting VM information. 

        if (host_statistics(host_port,  // As obtained from mach_host_self()
             HOST_VM_INFO,              // Flavor - many more in <mach/host_info.h>(host_info_t)&vm_stat,                  // OUT - this will be populated
             &host_size)                // in/out - sizeof(vm_stat). 
              != KERN_SUCCESS)         
            NSLog(@"Failed to fetch vm statistics"); // log error

        /* Stats in bytes */
        // Calculating total and used just to show all available functionality

        // This part is basic math. Counts are all in pages, so multiply by pagesize
        // Memory used is sum of active pages, (resident, used)
        //                       inactive,      (resident, but not recently used)
        //                   and wired (locked in memory, e.g. kernel)

        natural_t mem_used = (vm_stat.active_count +
                              vm_stat.inactive_count +
                              vm_stat.wire_count) * pagesize;
        natural_t mem_free = vm_stat.free_count * pagesize;
        natural_t mem_total = mem_used + mem_free;
        NSLog(@"used: %u free: %u total: %u", mem_used, mem_free, mem_total);


        return (int) mem_free;
    }
于 2013-09-25T11:55:14.267 回答
4

因此,在一些 Objective-C 专家的帮助下,我已经能够找到正在做我想做的事情的代码片段。我必须警告你,我不明白这个 Obj-C 代码到底是怎么做的,它被认为是“黑客”;但是,事实证明这是解决我的问题的最佳方法。

在插件 .mm 文件中:

#import <mach/mach.h>
#import <mach/mach_host.h>

extern "C"
{

    const int HWUtils_getFreeMemory()
    {
        mach_port_t host_port;
        mach_msg_type_number_t host_size;
        vm_size_t pagesize;

        host_port = mach_host_self();
        host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
        host_page_size(host_port, &pagesize);

        vm_statistics_data_t vm_stat;

        if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS)
            NSLog(@"Failed to fetch vm statistics");

        /* Stats in bytes */
        // Calculating total and used just to show all available functionality
        natural_t mem_used = (vm_stat.active_count +
                              vm_stat.inactive_count +
                              vm_stat.wire_count) * pagesize;
        natural_t mem_free = vm_stat.free_count * pagesize;
        natural_t mem_total = mem_used + mem_free;
        NSLog(@"used: %u free: %u total: %u", mem_used, mem_free, mem_total);

        return (int) mem_free;
    }

}

在我的硬件实用程序文件中:

    [DllImport("__Internal")]
    static extern int HWUtils_getFreeMemory();

#if UNITY_IPHONE && !UNITY_EDITOR
    public static int GetFreeMemory()
    {
        return HWUtils_getFreeMemory();
    }
#endif
于 2013-09-25T10:54:36.620 回答
1

在 Unity3D(iOS 和 Android)上读取像素时,我也会收到一些 GL_OUT_OF_MEMORY 错误。在我做了很多测试之后,主要问题是当我使用 ReadPixels 方法截屏时我的游戏的绘图调用太高(大约 > 40 个绘图调用)。也许你也应该调查这个因素。

于 2013-10-07T01:03:17.520 回答