YooAsset icon indicating copy to clipboard operation
YooAsset copied to clipboard

关于YooAsset的源代码相关的问题

Open xubaiself opened this issue 2 years ago • 9 comments

作者您好,最近一直在拜读YooAsset,因此特意开一个issue希望能和您交流下源代码。烦请您不要关闭这个issue,以后我的问题将都合并在这个issue,也希望您不吝赐教。

目前我的思路主要还是在整理整个框架的运行思路,目前已经有了些眉目。关于异步加载的部分是在YooAssetDriver中的Update函数中进行驱动的,也就是说在Unity的每一次update中会进行资源的更新,同时我看到在loader和provior中的update函数中会执行一个完整的加载流程不会中断。那这样的话会不会导致在某几个update中因为加载资源占用时间过多而导致卡帧的现象呢?

在一些文章中会说希望将异步加载放在协程中进行,但我自己尝试过在协程中加载资源,其实也是和您updatge中差不多的流程,一套加载完这种,所以协程异步加载资源应该是怎么样构建呢,或者说怎么样设置异步加载的时间将其分摊在不同的update中呢?

因为我目前还是在学习的状态,并未参加过上线项目的开发,也想这个问题想和您探讨下关于资源异步加载的时间分配问题,希望您不吝赐教。祝好!

xubaiself avatar Feb 19 '23 10:02 xubaiself

资源加载并不会太耗时,耗时大部分是花在了实例化上,所以针对这个问题,operation system代码里,采取了分帧处理逻辑来避免卡顿。

gmhevinci avatar Feb 20 '23 06:02 gmhevinci

unity的协程本质上也是在主线程里处理的,在mono内部update方法里按照顺序执行所有协程,你是干预不了的。

gmhevinci avatar Feb 20 '23 06:02 gmhevinci

哦哦,我懂了,非常感谢您的回答。

关于资源管理我还有一个问题,包括我自己之前在尝试写资源管理的时候也在思考这个问题,就是说从一个AssetBundle中加载的资源,如果不卸载Assetbundle那么该资源就没法被卸载是么?

因为往往是,当所有从AssetBundle中加载的资源的引用为0时AssetBundle的引用为0然后可以卸载AssetBundle。但是比如说a1和a2。从一个AssetBundle中加载,我现在不用a1了,但是a2一直被使用,那是不是a1没办法被单独卸载呢?AssetBundle似乎也没有提供卸载资源的API,只有加载资源和卸载AssetBundle的api。那这样我的理解就是a1没用了,但一直在内存中没法卸载,因为a2还依赖着这个AssetBundle。这样是不是就导致内存的被无效资源占用呢?这个问题应该在划分AssetBundle的时候解决么?

有这个问题主要是因为Resources那套api提供了load和unload资源的方法,而AssetBundle这边似乎只有load资源而不能单独unload资源。

xubaiself avatar Feb 20 '23 08:02 xubaiself

AssetBundle加载出来的资源对象,单独卸载也可以。但是对一个稳定的资源系统框架来讲,这是错误的行为,他会造成依赖链的不稳定,最主要原因就是GameObject对象无法卸载。

gmhevinci avatar Feb 22 '23 09:02 gmhevinci

可以参考YoAssets里面的OperationSystem, 他就是你所描述的, 将操作分配在每一个update中, 而且可以设置每一个AsyncOperationBase的执行时间再MaxSliceTime之间,除非那一帧的某一个操作太耗时。 所以说,有一系列各种资源加载、文件验证等等AsyncOperationBase的子类,都在OperationSystem里面被Update,保证每个操作在固定间隔时间内update。 至于你说的资源卸载问题,可以看到里面有继承IDispose接口的operation

  1. 当你的资源被引用的时候,这个operation虽然没有被代码引用了,但是里面的成员变量(UnityEngine.Object)还在被你代码里某些地方引用着,所以这个operation类还在内存里。
  2. 当这个资源引用的地方没有了(GameObject被destroy或者其他情况), 这个operation类就会进入被GC状态,这个时候就会调用这个operation的IDispose接口的方法,这个方法里减少该资源的引用计数。
  3. 在持有AssetBundle的BundleProvider里会在每帧update中去检测这个计数,计数到0了就会调用AssetBundle.Unload(true)去卸载资源了。
  4. 总结来说就是通过C#类自动进入GC状态去触发IDispose去自动减少引用计数来进行卸载ab包,相当于把资源减少引用计数的操作托管给了C#(CLR虚拟机), 这样一来就省去手动调用卸载的风险,减少一些心智负担,方便了很多。

MOMOLAXI avatar Mar 15 '23 17:03 MOMOLAXI

之前考虑过通过监测UnityEngine.Object是否销毁来做自动释放。后来发现问题太多就放弃了。

  1. 当这个资源引用的地方没有了(GameObject被destroy或者其他情况), 这个operation类就会进入被GC状态,这个时候就会调用这个operation的IDispose接口的方法,这个方法里减少该资源的引用计数。

这个需要OP常驻,然后每帧去检测Obj是否销毁。而且在OP创建完成之后,Obj可能还未加载完成,或加载失败。

gmhevinci avatar Mar 17 '23 02:03 gmhevinci

之前考虑过通过监测UnityEngine.Object是否销毁来做自动释放。后来发现问题太多就放弃了。

  1. 当这个资源引用的地方没有了(GameObject被destroy或者其他情况), 这个operation类就会进入被GC状态,这个时候就会调用这个operation的IDispose接口的方法,这个方法里减少该资源的引用计数。

这个需要OP常驻,然后每帧去检测Obj是否销毁。而且在OP创建完成之后,Obj可能还未加载完成,或加载失败。

确实是的,我之前也尝试过使用mono组件把引用计数通知回来,但是异常情况太多了。另一个情况又是new的对象不管了,看着非常刺眼,所以目前策略就是够用, 问题不大就行了。

MOMOLAXI avatar Mar 17 '23 13:03 MOMOLAXI

我这里有一个经验方法不知道合适不合适,方法如下: yoo已经设置的非常简单明了,对资源管理再上层封装一个context,通过context管理 “游戏逻辑上”的资源加载。 (1)对大一些的资源需求来说,比如战斗,我createContext(battle)生成一个battle的资源管理,里面专门处理战斗相关资源,在战斗中的资源加载通过battle-context.load去加载,战斗完成后,我直接在context卸载的时候,将整个战斗的资源句柄通通卸载。 (2)对一些小的资源需求来说,比如某个活动功能,我可以根据tag去管理,整体活动是一个context,我可以context.loadByTag("xxxtag")去加载和卸载当前tag的,在当前活动页面关闭后,我再conetxt.destroy("xxxtag") (3)默认的继承IDispose的句柄是最后的保证,保证我们有GC的时候,卸载了相应的资源

想当于 第1层:手动Destroy相关Instance,并把能清除的引用尽量清 第2层:从Context的区域删除当前功能的引用资源Handle 第3层:当整体大功能关闭时,直接ReleaseContext,并删除所有资源Handle 第4层:如果删不尽的,Yoo里面做IDispose的保护,保证它最后肯定是卸载掉的

不知道这种想法怎么样,目前我正在新项目使用Yoo,也希望对我的这种方法给一定的评判,谢谢啦

pengjugame avatar Aug 30 '23 12:08 pengjugame

不错的经验之谈。这个有点对象池的意思。

gmhevinci avatar Sep 01 '23 06:09 gmhevinci