unity3d:GC优化

https://edu.uwa4d.com/course-intro/0/165?purchased=true读书笔记

减少对象数量

在这里插入图片描述
在这里插入图片描述

内存对齐

在这里插入图片描述

在网络发送数据时使用共用体并缓存对象

// StructLayout使设计者可以控制类或结构的数据字段的物理布局  
 // Explicit与FieldOffset一起可以控制每个数据成员的精确位置  

[StructLayout(LayoutKind.Explicit)]
public class CSDataC
{
    / public members /
// FieldOffset控制字段所在的物理位置偏移为0  
    [FieldOffset(0)]
    public CSHeartBeatC stHeartBeat; // 心跳请求,字段无意义,占位用
    [FieldOffset(0)]
    public CSGM stGM; // Gm的字符串

利用union可以用相同的存储空间存储不同型别的数据类型,从而节省内存空间
发送时还可以缓存,防止new对象

public CSDataC GetCachedSendData(CS_CMD cmd)
		{
			int key = (int)cmd;
			CSDataC ret;

			if (!CachedDataCs.TryGetValue(key, out ret))
			{
				ret = new CSDataC();

				ret.@select((long)cmd);

				CachedDataCs.Add(key, ret);
			}

			return ret;
		}

使用泛型优化装箱

//一个带泛型类参数委托
public delegate void OnNotificationDelegate(EventData note);

public class EventData
    {
    }

    public class EventDataEx<T> : EventData
    {
        private T mData;

        public EventDataEx(T varData)
        {
            mData = varData;
        }

        public T GetData()
        {
            return mData;
        }
    }
    
//监听者解包
void OnEvBuildHomeTown(EventData data)
    {
        var exdata = data as EventDataEx<bool>;
        bool isBuild = exdata.GetData();
 
    }
    
//发送者
EventManager.Instance.DispatchEvent(Common.EventStr.BuildHomeTown, new EventDataEx<bool>(false));

不要使用可变参数,会产生临时数组

在这里插入图片描述

List使用时先确定长度,避免反复扩容new数组

在这里插入图片描述

C#对象池

internal static class ListPool<T>
    {
        // Object pool to avoid allocations.
        private static readonly ObjectPool<List<T>> s_ListPool = new ObjectPool<List<T>>(null, l => l.Clear());

        public static List<T> Get()
        {
            return s_ListPool.Get();
        }

        public static void Release(List<T> toRelease)
        {
            s_ListPool.Release(toRelease);
        }
    }

internal class ObjectPool<T> where T : new()
	{
		private readonly Stack<T> m_Stack = new Stack<T>();
		private readonly UnityAction<T> m_ActionOnGet;
		private readonly UnityAction<T> m_ActionOnRelease;

		public int countAll { get; private set; }
		public int countActive { get { return countAll - countInactive; } }
		public int countInactive { get { return m_Stack.Count; } }

		public ObjectPool(UnityAction<T> actionOnGet = null, UnityAction<T> actionOnRelease = null)
		{
			m_ActionOnGet = actionOnGet;
			m_ActionOnRelease = actionOnRelease;
		}

		public T Get()
		{
			T element;
			if (m_Stack.Count == 0)
			{
				element = new T();
				countAll++;
			}
			else
			{
				element = m_Stack.Pop();
			}
			if (m_ActionOnGet != null)
				m_ActionOnGet(element);
			return element;
		}

		public void Release(T element)
		{
			if (m_Stack.Count > 0 && ReferenceEquals(m_Stack.Peek(), element))
				HXLOG.Error("Internal error. Trying to destroy object that is already released to pool.");
			if (m_ActionOnRelease != null)
				m_ActionOnRelease(element);
			m_Stack.Push(element);
		}
	}

LinkedList

链表LinkedList具有泛型的特点,元素不连续分配,每个元素都有记录前后节点。
优点
插入、删除元素效率比较高。
缺点
不能进行下标索引访问,找元素只能遍历查找不方便
访问效率低

字符串使用StringBuilder

StringBuilder集成工具
https://blog.csdn.net/onelei1994/article/details/101054633

using System.Text;
using UnityEngine;

/// <summary>
/// 字符串优化类
/// </summary>
public class QString
{
    private static StringBuilder stringBuilder = new StringBuilder();
    private static StringBuilder shareStringBuilder = new StringBuilder();

    public static StringBuilder GetShareStringBuilder()
    {
        shareStringBuilder.Remove(0, stringBuilder.Length);
        return shareStringBuilder;
    }

    public static string Format(string src, params object[] args)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.AppendFormat(src, args);
        return stringBuilder.ToString();
    }

    public static string Concat(string s1, string s2)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.Append(s1);
        stringBuilder.Append(s2);
        return stringBuilder.ToString();
    }

    public static string Concat(string s1, string s2, string s3)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.Append(s1);
        stringBuilder.Append(s2);
        stringBuilder.Append(s3);
        return stringBuilder.ToString();
    }
}

public class QStringSample
{
    public void Test()
    {
        StringBuilder stringBuilder = QString.GetShareStringBuilder();
        for (int i = 0; i < 100; i++)
        {
            stringBuilder.Append(i);
        }
        Debug.Log(stringBuilder.ToString());
    }
}

匿名函数,带参数缓存住

https://zhuanlan.zhihu.com/p/25779397
当不使用外部变量的匿名函数时,编译器会把这个函数变成静态函数,在首次调用时初始化,之后就再也不会new新的对象。 当使用外部变量时,每次调用都会生成一个临时action变量,这个就是alloc的原因。
解决办法以及相关建议
这里会麻烦一点,需要声明一下:

public Action<int, int> pCall;
void Start()
{
 pCall = CallVariable;
 ... // 其他初始化代码
}
void FixedCall()
{
 table.Forecah(pCall);
}
void CallVariable(int k, int v)
{
  count = k + v;
}

协程优化

WaitForSeconds缓存住,防止每次new一个

UnityAPI

object.nameGC

object.name object.tag使用object.CompareTag

UnityAPI里所有返回数组都会产生GC

GetComponentsInChildren(List results);
在这里插入图片描述

materials产生GC

Physics.RayCastNonAlloc

UGUI的Text为空时,放个空格

UGUI的GC优化其它文章说的比较详细了,这里说一个比较容易忽视的一点,就是当Prefab中有大量空的Text,初始化的时候会有一个很严重的GC Alloc,这是因为在初始化时,会先初始化TextGenerator,如果Text为空,则会先按50个字来初始化,即50个字的UIVertex和50个字的UICharInfo,这种可以不让它为空,或者填一个空格进去来阻止。

Protobuf优化

反复创建的字节流,使用缓存,主要缓存字节流,和序列化对象,ObjectPool

发送时缓存

msSend.ResetStream();
ntf_battle_frame_data dataTmp = ProtoFactory.Get<ntf_battle_frame_data>(); 
        ProtoBufSerializer.Serialize(msSend.memStream, dataTmp);
        ProtoFactory.Recycle(dataTmp);//*************回收,很重要

针对每个池,回收单个对象时,单个对象数据初始化

public sealed class CmdWithFramePool : ProtoPoolBase<ntf_battle_frame_data.cmd_with_frame>
{
    protected override void RecycleChildren(ntf_battle_frame_data.cmd_with_frame netData)
    {
        if (netData.cmd != null)
        {
            ProtoFactory.Recycle(netData.cmd);
        }
    }

    protected override void ClearNetData(ntf_battle_frame_data.cmd_with_frame netData)
    {
        netData.server_frame = 0;
        netData.cmd = null;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

四夕立羽

你的鼓励将是我创作的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值