做了两个Unity项目.对于后期的优化和crash花了一些功夫.零零碎碎的感触记录如下.
优化最重要是从设计和规划入手.贯穿全局.到了后期上线出现问题才开始优化会花更多的精力.也会带来更多的问题.
如果项目管理.一个团队的战斗力应该表现在长期,可持续,稳定输出.而不是跟小学生做寒假作业似的.非要等到最后一天熬个夜完成.那样做不出什么像样的东西.
优化最重要的是找到瓶颈和优化点.不能盲目的做.看到别人说foreach不能用.就吭哧吭哧把整个项目所有foreach改一遍.力气花了.却没什么用.
前期不要在微观优化上下功夫.优化最重要是从设计和规划入手.精力要花在回报比最高的地方.
资源优化非常重要.前期要有规划.对于美术资源要有规范.
导入的模型顶点数.动画的骨骼数.用到的贴图大小都要有限制.用到的资源要心里有数.
UI不能随意设计扩张图素.所有用到的图素列在一张图上.
最好有个技术全程跟进.合理使用atlas.
资源导入要有规范.大小不是偶数的不允许导入.
因为不是4的整数倍unity无法压缩.会占用大量内存.
使用WeTest 或 UnityCube都能很容易的查出内存占用的问题
Profile里的内存.看Detail.虽然内存占用不太准.但大概问题还是能找出来的.
代码层面.对于设计要统一.
实现方法要有经验的人来review.一旦有不合理,低效率的代码加入.就如破窗效应.难以控制.
很多细节稍作注意就可避免.代码review不仅仅可以有效降低bug的迁入率.更重要的是,每个程序员在写代码的时候会知道.我写的代码是有人要看的.
这是一个立即的心理反馈.很多该注意的地方也就注意了.
这方面其实归为 微观优化.如果方案和资源有问题.在这方面扣是没有意义的.
有些优化的文章可以参考
如果对GC有要求.需要进行内存管理.只要看这两篇文章即可
https://onevcat.com/2012/11/memory-in-unity3d/
http://docs.unity3d.com/Manual/UnderstandingAutomaticMemoryManagement.html
但实做下来的体会是
入手的方向
1.减少总内存占用.审视当前内存的资源是否合理
2.减少内存分配.审视每一次Alloc.
using UnityEngine;
using UnityEditor;
using System.IO;
public class UIZOptimizeTool
{
[MenuItem("Tools/UITools/SceneUIZOptimize")]
public static void OptimizeSceneUIZ()
{
Canvas[] can = GameObject.FindObjectsOfType<Canvas>();
for (int indexCan = 0; indexCan < can.Length; ++indexCan)
{
RectTransform[] rectTrans = can[indexCan].transform.FindComponentsInChildren<RectTransform>(true, true);
for (int index = 0; index < rectTrans.Length; ++index)
{
if (null == rectTrans[index]) continue;
if (can[indexCan].gameObject == rectTrans[index].gameObject) continue;
ResetZ(rectTrans[index]);
}
}
}
[MenuItem("Assets/UITools/OptimzeUIZByFolder")]
public static void OptimizePrefabZByFolder()
{
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
if (string.IsNullOrEmpty(path)) return;
path = path.Substring(path.IndexOf("Assets") + 6);
path = Application.dataPath + path;
ProcessPrefab(path);
}
private static void ProcessPrefab(string path)
{
if (Directory.Exists(path))
{
string[] fileEntries = Directory.GetFiles(path);
for (int index = 0; index < fileEntries.Length; ++index)
{
ProcessPrefab(fileEntries[index]);
}
string[] dics = Directory.GetDirectories(path);
for (int index = 0; index < dics.Length; ++index)
{
ProcessPrefab(dics[index]);
}
}
else if (Path.GetExtension(path) == ".prefab")
{
string internalPath = path.Substring(path.IndexOf("Assets"));
GameObject load = (GameObject)AssetDatabase.LoadAssetAtPath(internalPath, typeof(GameObject));
if (null != load)
{
if (OptimizeObject(load)) AssetDatabase.SaveAssets();
}
}
}
[MenuItem("Assets/UITools/OptimzeUIZByPrefab")]
public static void OptimzePrefabZ()
{
GameObject[] sels = Selection.gameObjects;
for (int index = 0; index < sels.Length; ++index)
{
if (!IsPrefab(sels[index])) continue;
if (OptimizeObject(sels[index]))
{
AssetDatabase.SaveAssets();
}
}
}
private static bool OptimizeObject(GameObject obj)
{
bool ret = false;
RectTransform selfRect = obj.GetComponent<RectTransform>();
if (null != selfRect)
{
if (ResetZ(selfRect)) ret = true;
}
RectTransform[] rectTrans = obj.transform.FindComponentsInChildren<RectTransform>(true, true);
for (int transIndex = 0; transIndex < rectTrans.Length; ++transIndex)
{
if (null == rectTrans[transIndex]) continue;
if (ResetZ(rectTrans[transIndex])) ret = true;
}
return ret;
}
private static bool IsPrefab(GameObject obj)
{
return PrefabUtility.GetPrefabParent(obj) == null && PrefabUtility.GetPrefabObject(obj) != null;
}
private static bool ResetZ(RectTransform trans)
{
//CanvasRenderer renderer = trans.GetComponent<CanvasRenderer>();
//if (null == renderer) return false;
if (trans.localPosition.z != 0)
{
trans.SetLocalPositionZ(0);
UnityEngine.Debug.Log("reset UI position " + trans.name);
return true;
}
return false;
}
}