我正在使用以下功能统一加载和缓存资产捆绑包: webgl :
IEnumerator DownloadAndCacheAB(string assetName)
{
// Wait for the Caching system to be ready
while (!Caching.ready)
yield return null;
// Load the AssetBundle file from Cache if it exists with the same version or download and store it in the cache
using (WWW www = WWW.LoadFromCacheOrDownload(finalUrl, 1))
{
yield return www;
if (www.error != null)
{
Debug.Log("WWW download had an error:" + www.error);
}
AssetBundle bundle = www.assetBundle;
if (assetName == "")
{
GameObject abObject = (GameObject)Instantiate(bundle.mainAsset, gameObject.transform.position, gameObject.transform.rotation);
abObject.transform.parent = this.transform;
SetTreeShaderSettings(abObject);
}
else
{
GameObject abObject = (GameObject)Instantiate(bundle.LoadAsset(assetName), gameObject.transform.position, gameObject.transform.rotation);
abObject.transform.parent = this.transform;
}
// Unload the AssetBundles compressed contents to conserve memory
bundle.Unload(false);
} // memory is freed from the web stream (www.Dispose() gets called implicitly)
}
每当我要删除对象时,我都会使用此功能。
public void RemoveBundleObject()
{
//if (www != null)
//{
// www.Dispose();
// www = null;
if (loadBundleRef != null)
{
StopCoroutine(loadBundleRef);
}
if (this.gameObject.transform.childCount > 0)
{
Destroy(this.gameObject.transform.GetChild(0).gameObject);
System.GC.Collect();
}
//}
}
如您所见,我正在删除第一个孩子(我是从资产捆绑包中获得的),然后调用GC Collect强制执行垃圾收集器。但是问题是,每次卸载/销毁对象时,内存都不会释放。现在您会认为我如何测量内存?我正在使用here中的WebGLMemoryStats。 在资产捆绑负载反复迭代之后,我得到了这个。
编辑: 我现在正在使用WebRequest类下载Assetbundle(find here),但仍然无法释放内存,有时会出现aw snap错误。
即使我试图一次加载一个空的webgl构建,一次又一次地增加内存堆,然后有时我会遇到aw snap或内存错误以及chrome崩溃的情况。
如您所见,初始负载约为1.2 Mb,但是当我刷新页面并进行快照时,快照带来了增加的内存。
答案 0 :(得分:3)
请注意,您永远无法使它发挥出您认为的完美功能。有一些用于清理垃圾和卸载资产的实用程序,但是即使您遵循所有最佳实践,您仍然可能无法让Unity清理所有垃圾(它在后台做了很多工作,会保留分配的内存,并且您所占的空间不大可以做到)。如果您对此感到好奇,建议您在Heap Fragmentation和Memory Optimization Guide上写下它们。
就您对特定项目所做的事情而言,至少可以进行一些改进:
1)避免不惜一切代价使用WWW
类。它创建的垃圾多于其价值,不能总是很好地清除,并且在最新版本的Unity中已过时。使用UnityWebRequest下载捆绑软件。
2)不要养成只加载单个资产然后卸载该捆绑包的习惯。如果在运行时发生大量负载,这将导致崩溃,并且是管理软件包的一种非常低效的方式。我注意到您正在呼叫bundle.Unload(false)
,这意味着捆绑包正在卸载,而装载的预制资产却没有。我建议以一种您可以的方式进行重组:
bundle.Unload(true)
3)调用StopCoroutine(loadBundleRef);
时要小心(如果loadBundleRef
是运行Web请求和捆绑加载逻辑的Coroutine
对象)。中断这些异步操作可能会导致内存问题。您应该有一些地方可以确保Web请求和捆绑包加载完全完成,或者在失败时抛出并让游戏恢复。禁止类似StopCoroutine
之类的东西来打扰他们。
4)System.GC.Collect();
速度很慢,并且垃圾收集还是会定期进行。谨慎使用它,您可能还需要先调用Resources.UnloadUnusedAssets
,然后再调用它。
答案 1 :(得分:0)
也请考虑@Foggzie答案以获取一些最佳做法(我使用了其中一些)!
我的代码或测试过程存在两个问题。
Unity内置WWW.LoadFromCacheOrDownload很烂!认真!为什么呢Ben Vinson和unity也在他们的博客中进行了解释:
与内存相关的问题的另一个来源是IndexedDB文件系统 由Unity使用。每当您缓存资产捆绑包或使用任何 与文件系统相关的方法,它们存储在虚拟文件系统中 由IndexedDB支持。
您可能没有意识到的是此虚拟文件系统已加载 Unity应用程序启动后立即进入并保留在内存中。 这意味着如果您使用默认的Unity缓存机制 对于资产捆绑包,您要将所有捆绑包的大小添加到 游戏的内存需求,即使不是 已加载。
在his blog中明确提到了Unity,使用UnityWebRequest代替LoadFromCacheOrDownload:
如果要使用新的UnityWebRequest API,则可以使用WWW构造函数代替LoadFromCacheOrDownload()或使用不带哈希/版本参数的UnityWebRequest.GetAssetBundle()(不带散列/版本参数)来最大限度地减少资产束缓存的内存开销。
然后在XMLHttpRequest级别使用替代的缓存机制, 将下载的文件直接存储到indexedDB中,绕过了 内存文件系统。这正是我们最近开发的 它在资产商店中可用。随时在您的手中使用它 项目并根据需要对其进行自定义。
页面重新加载上的内存增加问题似乎与FireFox内部机制有关。但是由于我在检查内存时打开了dev工具,因此它在chrome中发生。
一旦我在chrome中测量我的选项卡内存,开发工具就会打开,因此每次刷新页面时它都会增加内存。这个原因由Unity official at forum
之一定义需要注意的一点是,在重新加载页面时分析内存使用情况时 在Firefox中,请确保具有Firefox Web控制台(和调试器) 窗口关闭。 Firefox的行为是,如果打开了Web控制台, 使Firefox JS调试器保持活动状态,从而将所有访问的页面固定到 被缓存在内存中,永不回收它们。关闭Firefox网站 页面控制台允许从内存中释放旧页面。
我不知道Chrome是否可能具有类似的行为,但可以肯定的是 措施,最好关闭其网络控制台以确保它不会 使页面保持活动状态。
如果某人有一个可以发布的公开测试用例,那 将有助于查明来源。
但是实际上my test suggest表示在解决Google Chrome浏览器时,fireFox仍然存在此问题。
记住,经过长时间的努力,我得到了这个答案。