将预制体动态加载到场景当中,包括其依赖项(贴图,网格,材质等)
Resource.Load()
这是Unity内置的一种资源管理方式,现在已经不推荐,除非是项目测试Demo,或者小型项目中可以用用
内存情况:
所有 Resources 文件夹中的资源在构建时会被合并到一个序列化文件中(resources.assets,在打包后的Date目录下)。首次调用 Resources.Load 时,Unity 会解析这个序列化文件,加载所需的资源到内存。后续加载同一资源时,如果资源已在内存中,则直接引用,不会重复加载。
依赖项加载
当调用Resources.Load加载预制体时,Unity不仅会加载该预制体本身,还会自动加载其直接引用的所有依赖资源(如材质、贴图、模型等)
验证
下面是使用MemoryProfiler插件验证的过程:
在Resource中加载一个预制体FireBall,这个物体上有FireFist精灵,和粒子系统间接引用的FireCore材质
public class ResourceLoader : MonoBehaviour
{
GameObject prefab;
void Start()
{
prefab = Resources.Load("Skill/FireBall") as GameObject;
}
}
如图,预制体直接依赖项被加载至内存,而间接依赖项FireCore并没有被加载(间接依赖项是在GameObject.Instantiate实例化之后才会被加载
内存释放
只能手动清理或者场景切换的时候清理
释放单个资源:Resources.UnloadAsset()
释放某个未被引用的资源(例如未实例化的预制体、材质、纹理等)。

注意:
如果资源已被实例化(例如通过
Instantiate生成 GameObject),则必须销毁所有实例后,才能成功释放。如果资源被其他对象引用(例如材质被某个 GameObject 使用),则无法释放。
GameObject prefab = Resources.Load<GameObject>("Prefabs/Enemy");
Resources.UnloadAsset(prefab); // 仅当prefab未被实例化或引用时生效释放所有未使用资源:Resources.UnloadUnusedAssets()
释放所有未被引用的资源(包括未被实例化的预制体、未被引用的材质/纹理等)。

使用场景:
切换场景后,自动调用释放旧场景的资源
手动清理
// 销毁所有实例
Destroy(enemyInstance);
// 触发垃圾回收(可选)
System.GC.Collect();
// 释放未使用资源
Resources.UnloadUnusedAssets();静态路径资源
指的是直接拖拽到Inspector面板上Public字段的资源
内存情况
这种资源的内存情况就比较简单了,基本默认随场景一起加载,包括其依赖项(不清楚是不是直接依赖,有兴趣的可以自己去试试)
非激活状态的场景物体引用
如果这个物体在场景中处于非激活状态,那么资源还会加载到内存吗?答案是会的。
验证:
简单写了个测试代码如下,预制体RockBall依赖精灵RockBall
public class PrefabLoader : MonoBehaviour
{
public GameObject prefab;
}

结论
即使物体在场景中处于非激活状态,资源还是会加载到内存。
所以各位在使用对象池的时候尽量让池中的物体使用同样的依赖项,不然如果是不一样的贴图或者材质,内存占用会比较大。
一个idea:使用SO文件储存静态引用到Resources目录下
由上可知,Resources目录不会加载间接引用,博主灵机一动:诶,如果我使用SO容器记录每一个预制体的引用,然后使用Resources.Load来加载这个SO容器,那不就既可以灵活加载资源,又避免了Resources加载内存占用的问题了?
话不多嗦,开始实践:
实现过程
[CreateAssetMenu(fileName = "AssetsManager", menuName = "Asset/AssetsManager")]
public class AssetsManager : ScriptableObject
{
private static AssetsManager _assetsManager;
public static AssetsManager instance
{
get
{
if (!_assetsManager)
{
if (!(_assetsManager = Resources.Load("AssetsManager") as AssetsManager))
Debug.LogError("no asset Manager in path");
}
return _assetsManager;
}
}
[Header("预制体1")]
public GameObject prefab1;
[Header("预制体2")]
public GameObject prefab2;
}然后在Resources目录下建立这个SO文件,调用处使用AssetsManager.instance
public class SO_PrefabLoader : MonoBehaviour
{
GameObject prefab1;
GameObject prefab2;
void Start()
{
prefab1 = AssetsManager.instance.prefab1;
}
}SO文件中拖拽的prefab1是自定义文件夹Prefabs下的WaterBall,其有间接依赖项材质Water
prefab2是是自定义文件夹Prefabs下的Thunder,有其同名的多个直接依赖
如果能够灵活加载内存,那么内存里面只会存在prefab1即WaterBall,否则两个预制体都会存在
结果

可以看到WaterBall的直接依赖都在,但是没有间接依赖,符合Resources.Load的特性

不幸的是,预制体Thunder也在,而且其直接依赖也在内存中(▼ヘ▼)
结论
博主的想法失败了,可以得出结论:
如果预制体的引用在 SO 中是通过 public GameObject prefab 直接拖拽赋值的(而非动态路径加载),那么Unity会隐式调用Resources.Load进行加载,而且SO文件中的所有引用的预制体都会被加载
使用AB包
AssetsBundle,作为一个方式灵活,支持热更的资源打包方式,通过将资源分布在不同的AB包中可以减少运行时的内存压力,可以动态地加载和卸载AB包,继而有选择地加载内容。
可以去看看Unity AssetsBundle 详解_unity assetbundle-CSDN博客
内存情况:
打包时
当将一个预制体打包到AB包中时,Unity会:
序列化预制体本身:将预制体的GameObject结构、组件、脚本参数等数据存入AB包。
自动打包所有依赖项:预制体引用的资源(如材质、纹理、模型、动画等)都会被隐式打包到同一个AB包中,除非这些依赖项已被明确分配到其他AB包。(所以为了避免冗余资源打包,需要进行资源分包管理)
加载时
LoadFromFile(包括异步加载,
直接从磁盘读取,内存占用较小(仅存储文件头信息)
建议异步加载避免主线程堵塞
适用于不压缩或LZ4压缩格式的AB包
网络加载与之类似
LoadFromMemory
适用于需要加密或动态生成的AB包
将整个AB包数据加载到内存中,内存占用高(文件大小 × 1.3~1.5倍)
验证
将多个预制体打包在同一个ab格式的包skill.ab下,其中预制体WaterBall包含间接依赖项材质WaterCore
public class AB_Loader : MonoBehaviour
{
GameObject prefab;
private void Start()
{
AssetBundle assetBundle = AssetBundle.LoadFromFile("Assets/AssetBundles/Windows/skill.ab");
prefab = assetBundle.LoadAsset<GameObject>("WaterBall");
}
}
从上图可以看到,内存当中的skill.ab占用仅8.5kb,仅存储了了头信息

可以看到,间接依赖项WaterCore也被加载到内存中
内存释放

(1) AssetBundle.Unload(bool unloadAllLoadedObjects)
Unload(true):卸载AB包并销毁所有从中加载的资源 风险:若其他对象引用这些资源,会导致“Missing”错误(留下神秘粉色材质)
Unload(false):仅卸载AB包文件,保留已加载的资源 风险:资源残留,需手动调用
Resources.UnloadUnusedAssets()
(2) 建议实践方法
加载资源后立即调用
AssetBundle.Unload(false)释放AB包文件内存确保无引用后,通过
Resources.UnloadUnusedAssets()释放资源使用引用计数或依赖管理框架(如Addressables)管理复杂依赖
使用Addressable管理
鉴于Unity提供的ab包API实在有些简陋,就连生成ab包都要手动写Editor代码,ab包也需要手动卸载,于是就有了Addressable插件
【游戏开发探究】Unity Addressables资源管理方式用起来太爽了,资源打包、加载、热更变得如此轻松(Addressable Asset System | 简称AA)_unity aa-CS
参与讨论
(Participate in the discussion)
参与讨论