干货:u3d手游内存该如何进行优化?
发表于2016-11-10
unity3d手游可优化的地方有很多,如专门针对CPU和GPU的优化,这些都是各个制作团队集中优化处理的地方,u3d关于内存的使用以及优化也是一个重要的方向。如何才能合理的使用内存,避免内存泄露,下面说说u3d内存的那些事。
1)堆和栈是目前主流的操作系统划分动态内存的方式,c#通过区分值类型和引用类型来支持堆和栈,其中值类型在堆中,引用类型在栈上。知道了内存的分配形式,我们是不是可以随意的往堆和栈中加入元素,经常使用foreach的开发者知道,要避免foreach的使用,foreach代码中会进行一些预处理(如下),每次循环都会创建一个enumerator对象,这使得每次循环都需要调用一次GC机制来回收,在手机上将会占用过多的CPU来就行内存分配管理。
foreach (SomeType s in someList)
s.DoSomething();
...into something like the the following:
using (SomeType.Enumerator enumerator = this.someList.GetEnumerator()){
while (enumerator.MoveNext()) {
SomeType s = (SomeType)enumerator.Current;
s.DoSomething();
}}
2)u3d中纹理图片对内存在占用比较多,如何既能满足游戏纹理的需求,又可以减少内存的占用。项目中一般会有几种方案,首先是对图片进行高效的压缩,手游开发中,项目开发中会针对不同的纹理显示需求来就行不同的压缩方案,高清晰无压缩采用RGBA32方法,中清晰中等压缩采用RGBA16加上Dithering方式,低清晰高压缩采用ETC1加A方式,或者采用PVRTC4方式都可以。总之在项目中尽可能的使用GPU直接支持的图片格式,不仅仅占用内存低,而且性能好。然后还可以对纹理进行texturepacker处理,纹理在内存中都是二的次方形式出现,对于10*10的纹理会申请16*16来存储,所以为了节约资源,可以讲纹理使用前用texturepacker处理,减少内存载入纹理的分配。
3)网格资源在复杂的游戏中占用内存也比较多,对于网格方面的优化,需要考虑多方面因素,首先当然是合并网格(如下),在降低内存的同时,还是分析合并网格后带来的其他不必要内存的增加,如合并的网格前99个没有color数据,1个有color数据,那合并后会使得这100个网格都具有color数据,从而增大内存,有取舍的合并,可以带来最好的内存优化。
public class CombineMeshes : MonoBehaviour
{
void Start()
{
MeshFilter[] mesh_filters = GetComponentsInChildren();
CombineInstance[] combine_instance = new CombineInstance[mesh_filters.Length];
int i = 0;
while (i < mesh_filters.Length)
{
combine_instance[i].mesh = mesh_filters[i].sharedMesh;
combine_instance[i].transform = mesh_filters[i].transform.localToWorldMatrix;
mesh_filters[i].gameObject.SetActive(false);
i++;
}
transform.GetComponent().mesh = new Mesh();
transform.GetComponent().mesh.CombineMeshes(combine_instance );
transform.gameObject.SetActive(true);
}
}
4)简单的说内存泄露是分配出去的内存应该收回却没有收回来,内存的泄露本身是不会对用户产生什么危害,用户在游戏过程中基本体会不到泄露的存在,但是如果内存泄露进行了堆积,不断的消耗系统的内存,会导致游戏卡顿,机子发热,甚至直接导致游戏崩溃。如何预防、检测避免内存泄露,首先c#编程过程中会随着时间的推移产生内存增长消耗,因此开发过程中要尽早在真机里测试,移动设备对内存的要求比模拟器苛刻,真机测试是非常有必要的,c#的堆是宝贵的资源,游戏开发中可以自定义对象池,避免平凡的申请释放内存块,另外可以考虑用栈来协助堆的使用。这需要考虑到值类型和引用类型的互换。对于字符串的处理,可以使用StringBuilder。在遇到内存泄露时候可以用时相应的办法进行快速的查找,检测,如mono内存泄露,凭开发经验来一步步查找内漏效率很低,可以尝试使用Wetest平台工具来进行mono内存块对比。定位mono内存,从而尽快找到,并解决内存泄露。