Unity3d工作内存:加载和卸载预设。

6
我真的需要帮助! 我不知道如何使用预制件和卸载。
我有以下情况: 我从Xcode在IPad上运行我的应用程序。 Unity版本为4.3.1 Pro。 使用以下工具监视内存: Xcode Debug Navigator Xcode Instruments Unity Profiler
我执行以下步骤: 0) Unity从空场景开始。 使用的内存 XCODE Debug Navigator: 11 mb Instruments: 26.4 mb Unity Profiler: used total 13.2 reserved total 13.7
1) 从资源文件夹中加载预制件。
prefab = Resources.Load("Room1"); 

XCODE调试导航器使用内存:30.8 mb,Instruments使用内存:49.54 mb,Unity Profiler使用内存:已用总量19.8,保留总量20.4

2)实例化预设

go = (GameObject)Instantiate(prefab); 
go.name = "Room1"; 

XCODE调试导航器: 31.2兆字节 仪器: 50兆字节 Unity分析器: 使用总计20个保留总计20.7

3) 销毁场景上的所有对象 - 内存未改变

Transform[] tr = FindObjectsOfType<Transform>(); 
for (int i = 0; i < tr.Length; i++) 
{ 
    GameObject goo = tr.gameObject; 
    if (goo.name != "Main Camera") 
    {
        Destroy(goo); 
        goo = null;
    } 
} 

XCODE Debug Navigator: 31.1 MB Instruments: 49.93 MB Unity Profiler: used total 19.8 reserved total 20.4

4) 调用 Resources.UnloadUnusedAssets(); - 内存没有改变

5) 调用 System.GC.Collect(); - 内存没有改变

6) 对预制体调用 UnloadAsset:Resources.UnloadAsset(prefab); - 内存没有改变

7) 调用 Resources.UnloadUnusedAssets(); - 内存部分清理

XCODE Debug Navigator: 21.9 MB Instruments: 40.79 MB Unity Profiler: used total 13.2 reserved total 13.9

在分析器中,我看到删除了所有在预制体中使用的纹理

8) System.GC.Collect(); - 内存没有改变

9) 加载空场景 - 内存没有改变

这里有另一个有趣的时刻:

当应用程序进入后台并启动另一个应用程序时,已使用的RAM大小大大减小,当我调用Unity应用程序时,内存返回到带有空场景的第一个大小。

我的问题如下:

1)为什么在删除预制体并调用UnloadUnusedAssets后内存没有完全清除 - 在Instruments和Xcode中可以看到,但在Profiler中我们看到内存几乎完全释放了?

2)清理内存回到初始大小是真实的吗?

3)我所有的步骤都正确吗,还是我做错了什么?

您可以在此处下载测试项目: http://gfile.ru/aa5on

非常感谢您的回复。


附注: 请先尝试更新您的Unity 3D。 - Raptor
2个回答

9

前言

能够意识到RAM使用情况是很好的。但问题是:你是否遇到过内存使用问题?如果没有,那么你现在所做的还为时过早。

一些想法

以下是一些需要考虑的想法:

  1. 阅读重要文章:http://docs.unity3d.com/Manual/MobileProfiling.html
  2. Unity内存和mono内存是不同的。Mono永远不会将内存归还给操作系统:

    一旦你分配了一定量的内存,它就被保留给mono而不是操作系统。即使你释放了它,它也只会在Mono内部变得可用,而不是对操作系统可用。Profiler中的堆内存值只会增加,永远不会减少。

  3. Prefabs和game objects只是一堆链接,因此它们的内存占用量不像资源那样大。
  4. Object.Destroy 不会立即销毁对象

    实际的对象销毁总是延迟到当前Update循环之后,但在渲染之前一定会完成。

  5. Resources.UnloadUnusedAssets是异步的。它不会立即卸载所有内容。
  6. Unity的文档中没有提到Resources.UnloadAsset(Object assetToUnload)将卸载由assetToUnload引用的资源。

解释

我不能称自己为Unity和Mono内存管理专家。但以下是我理解发生的情况:

  1. 1) 从资源文件夹加载预设

    预设已经被加载,它所引用的所有资源也一同被加载,内存使用量增加了。现在一切都很清楚。

  2. 2) 实例化预设

    内存使用量稍微增加了一些,以容纳预设的克隆体。

  3. 3) 销毁场景上的所有对象 - 内存未改变

    有趣的事情来了 :) 实际上,根据Unity的性能分析器,内存使用量已经改变了:它与实例化预设之前相同。因此,看起来Unity已经释放了与预设实例直接相关的一些内容。但是,正如它所说的,mono不会将内存返回给操作系统(即使它这样做了,现在还不是它这样做的时候)。

  4. 4) 调用 Resources.UnloadUnusedAssets() - 内存未改变

    Resources.UnloadUnusedAssets 在这里无法卸载任何东西,因为仍然没有未使用的资源:虽然对象已经被标记为销毁,但实际上垃圾回收还没有发生。

  5. 5) 调用 System.GC.Collect(); - 内存未改变。

    这是因为它是由mono管理的内存。

  6. 6) 调用预设 Resources.UnloadAsset(prefab);

    我相信内存使用量在这里已经略微下降了(大约100K-200K左右),但你没有注意到。但正如我上面提到的,UnloadAsset 不会卸载由你传递给UnloadAsset 的对象引用的资源。

  7. 7) 调用 Resources.UnloadUnusedAssets(); - 内存部分清理

    在步骤5中,您调用了GC.Collect(),垃圾回收已经发生,现在一些Unity资源没有被引用,因此可以最终释放它们。这就是为什么内存已被释放。

  8. 8) System.GC.Collect(); - 内存未改变

    解释如上所述

  9. 9) 加载空场景 - 内存未改变

    所有可能被释放的东西都已经被释放了。因此,内存使用量没有改变。


1
嗨,Sergey。非常感谢您的回复。我的内存问题是这样的:我的Unity应用程序作为一部分嵌入在XCode本地应用程序中。当我第一次从主应用程序调用Unity应用程序时,它会启动,但当我需要返回到主应用程序时,我会调用pause() unity。当我加载新场景或加载assetbundles时,普通应用程序的内存总是增加。结果是 - 当应用程序的大小变大时 - 应用程序会因内存错误而失败。 - madmik
2
我明白了。这里需要关注的第一件事是尝试减少纹理的内存使用量。您是否使用纹理压缩?是否有可能在不降低质量的情况下使某些纹理更小?然后,在暂停Unity播放器之前,您需要卸载尽可能多的资源。您可以尝试对每个已加载的资源(主要是纹理)调用Resource.UnloadAsset(我从未尝试过,但应该有效),或者您可以加载一些空白的“暂停”场景并调用Resources.UnloadUnusedAssets。 - Sergey Krusch

0

嗯,也许我需要从另一个角度来看待这个问题 - 在Unity应用程序暂停时清除内存?也许有人知道如何做到这一点? 或者在我尝试启动暂停的应用程序时重新启动它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接