unity内存优化和客户端表格读取方法内存比较

1. Resource.UnloadAsset()清理引用资源 和destroy()清理实例化资源 
2.Load出来的Assets其实就是个数据源,用于生成新对象或者被引用,生成的过程可能是复制(clone)也可能是引用(指针)
当你Destroy一个实例时,只是释放那些Clone对象,并不会释放引用对象和Clone的数据源对象,Destroy并不知道是否还有别的object在引用那些对象。
等到没有任何 游戏场景物体在用这些Assets以后,这些assets就成了没有引用的游离数据块了,是UnusedAssets了,这时候就可以通过 Resources.UnloadUnusedAssets来释放,Destroy不能完成这个任 务,AssetBundle.Unload(false)也不行,AssetBundle.Unload(true)可以但不安全,除非你很清楚没有任何 对象在用这些Assets了。
配个图加深理解:
--------------------------------------------------------------------------------
关于客户端读表有多种方式
1.最简单的就是xml表的读取,可以使用c#的库来读,也可以使用官方推荐的一个xml解析包来读,官方推荐当然更好,因为包含的库比较少,而且也高效,c#的xml读取会增加几m的包大小。
2.使用csv读取。这种格式存成txt格式,方便用excel编辑。相比xml来说,该方法更好,因为不需要额外的包来解析xml,只需要读取tet来解析成对应数据就行。解析自己写,很简单。但是大量text的读取 字符串解析,也会造成内存过去,和效率表现一般。
3. 使用序列化方法读取:该方法比上面2种方法 效率都高,内存占用都少,但是用法稍微复杂点。但是对于MMO的话 也许这个是较好的选择方式。用法:根据表的内容来定义序列化的结构体参数,也就是说代码定义好的key从表去读。把所有数据都存到一个prefab中。最后打包使用的是prefab的数据。就不需要解析表了。也可以存成byte文件。
该方法效率很高,内存占得也少。缺点是使用不方便,策划每加一张表,都需要程序来定义结构体。而且在后边更新表的时候,也需要重新制作prefab来更新数据。

---------------------------------------------------------
关于unity官方的内存:
1. 首先有个总内存叫Totalresercerdmemory,其次有个allocate内存,这个是游戏运行使用内存,再次有个unusedreserverdmemory,该内存是未使用的临时内存。Totalresercerdmemory=allocate+unusedreserverdmemory;一般情况下unusedreserverdmemory最好是只占总内存的很小的百分比会比较好。
但是部分算法 会极大的消耗unusedreserverdmemory内存。1 频繁的字符串连接和解析。2 频繁的调用可以返回list类型函数,像读取xml表就需要经常返回很大的table数据,这个会极大消耗总内存。这也是为什么客户端读表用序列化更好。 频繁字符型解析推荐使用stringbuilder。频繁的临时变量或者list生成,建议定义一个全局的list 每次都用该list来计算 然后返回。这样就不会创建很多临时内存。千万不要在函数内new一个list返回出来,虽然看起来还行,但是频繁调用很消耗内存。
2 其他的内存优化包括图集整理,及时释放,和对象池的使用。如果场景切换的时候 要加载大量数据的时候,可能会使临时内存增加,建议切换场景先切换到空场景,进行内存释放,释放完后再切换到目标场景。
4.System.GC.Collect(0,System.GCColletionMode.Optimized) 可以在update里边 适当时间调用这个,根据情况来释放内存。
System.GC.Collect(0,System.GCColletionMode.Forced) 在切换场景的时候 强制释放内存。
还可以在切换场景的时候调用System.GC.RemoveMemoryPressure(byte)和System.GC.AddMemoryPressure(byte),来告诉gc有多余内存需要释放,也可以在通用的读表的地方 调用,读完就释放。
------
关于用Profiler监控内存问题:Profiler.GetTotalReserverdMemory()=Profiler.GetTotalunusedReserverdMemory()+Profiler.GetTotalAllocatedMemory()
总内存=垃圾(临时)内存+实际分配内存,程序占得内存为总内存。该数据在PC上可以实时监测到内存大小,比如我们游戏是300=120+180这个水平。但是在Android设备上消耗总内存也是300M左右,但是输出的结果为110=5+100左右,和实际内存相差很大。根据我们推断,在pc上unity是完全自己管理内存,所以他知道所有内存池的分配。但是在Android上可能系统底层本身对应用分配了一个内存池,unity也有一个内存池,但是属于系统池内。unity只管理自己的内存,Android底层内存他管理不到,所以数据也不一样。Android想要获取实际内存 可能还是需要去系统获取。系统和unity内存池都有一个冗余部分。
总结:
1.切换场景释放资源和GC
2.内存总量减少,压缩分类图集。
3.碎片化减少,少用string的分割和连接,少在临时函数里new list。
4.配置表采用序列化的方式。
5.在合适的时候释放资源,比如当ui打开过多,或者隔一段时间,或者在某时刻内存过大。但是释放内存肯定会卡顿一下,所以时机要选好,比如boss开始动画,结束动画 ,在切换ui可以load一会儿的地方。为避免战斗卡顿,一定不能在战斗里边随意释放。
6.内存只能尽量减少,尽量避免碎片化,不可能完全避免。
----------
文件的读写xml csv 序列化,csv自己解析 比较好 但是大量数据内存大 效率不好。最好的是序列化。序列化有2种方式:1.是保存成prefab模式,直观 好看 参考fbd.cs。2.是保存成byte文件:效率更高。因为unity的prefab序列化过程可能还需要申请临时内存 保存临时数据。不过我觉得差不多吧。
[Serializable]
public class People
{
    public string Name { get; set; }
    public int Age { get; set; }
}//prefab 模式就是在mono里定义public的 People对象,把数据写进去,存成prefab。unity编辑器方便的查看修改序列化内容。
void Write(){//序列化写byte文件
FileStream fs = new FileStream("Asset\test.byte", FileMode.Create);
BinaryFormatter bf = new BinaryFormatter();
List<People> ps = new List<People>();//也可以只new 一个对象
ps.Add(new People() { Name = "gg", Age = 24 });
ps.Add(new People() { Name = "yy", Age = 23 });
bf.Serialize(fs, ps);
fs.Close();
}
void Read(){//读byte文件
FileStream fs = new FileStream("Asset\test.byte", FileMode.Open);
BinaryFormatter bf = new BinaryFormatter();
List<People> ps = bf.Deserialize(fs) as List<People>;
debug.log(ps[0].name)
//http://www.cnblogs.com/ustcwhc/archive/2011/11/01/2232195.html
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值