gc使用标记清除策略
标记清除 分为2个阶段
1.每个分配的gameobject 通过一个额外的数据位追踪,是 否标记,标记为flase,标识它尚未被标记,当收集开始时,它通过设置对象的标示为true,标记所有依然你对程序可访问的对象,对程序而言,任何没有被引用的对象本质是不可见的,而这些对象可以被GC回收
2.设计迭代这类引用,并给予它的标记状态决定它是否回收,如果对象被标记,那么在某处仍然引用他,gc将无视他,如果他没有被标记,那么他是回收的候选者
垃圾回收策略
触发回收的好时机是加载场景时,当游戏暂停时,再打开菜单界面后的瞬间
装箱:将值类型转换为引用类型称为装箱
拆箱:将引用类型转换为值类型称为拆箱
class Program { static void Main(string[] args) { int i = 128; object obj = i; obj = 512f; i = (int)obj; } //尝试将obj拆箱到一个不是最新赋值的类型时,将引发 //Unhandled exception. System.InvalidCastException: Unable to cast object of type 'System.Single' to type 'System.Int32'. }
1.struct是指类型,class是引用类型
public class DamageResult { public Character attacker; public Character defender; public int totalDamageDealt; public DamageType damageType; public int damageBlocked; // etc. } public void DealDamage(Character _target) { DamageResult result = CombatSystem.Instance.CalculateDamage(this, _target); CreateFloatingDamageText(result); } public struct DamageResult { // ... } //当使用目的是在向程序某处发送数据库,且数据的持续时间不需要超过 //当前作用域,那么可以使用struct来替代
2.数组的区别
TestStruct[] dataObj = new TestStruct[1000]; for(int i = 0; i < 1000; ++i) { dataObj[i].data = i; DoSomething(dataObj[i]); } However, the following, functionally equivalent, code would not result in any heap allocations since the struct objects being used are value types, and hence, it would be created on the stack: for(int i = 0; i < 1000; ++i) { TestStruct dataObj = new TestStruct(); dataObj.data = i; DoSomething(dataObj); } void TestFunction() { string testString = "Hello"; DoSomething(testString); Console.WriteLine(testString); //Debug.Log(testString); } void DoSomething(string localString) { localString = "World!"; } TestFunction(); 这个代码还是打印hello
1.通过值传递值类型,只能修改其数据的副本值
2.通过引用传递值类型,可以修改传入的原始数据
3.通过值传递引用类型,就可以修改原始引用的对象
4.通过引用传递引用类型,可以修改原始的引用的对象数据集
3.数据布局的重要
public struct MyStruct { int myInt; float myFloat; bool myBool; string myString; } MyStruct[] arrayOfStructs = new MyStruct[1000]; 对比 int[] myInts = new int[1000]; float[] myFloats = new float[1000]; bool[] myBools = new bool[1000]; string[] myStrings = new string[1000];
4.对字典键使用obj.GetInstanceID();
5.unity api中的数组开销
int[] myInts = new int[1000]; float[] myFloats = new float[1000]; bool[] myBools = new bool[1000]; string[] myStrings = new string[1000];
6 foreach巡回会在堆上分配一个Enummerator的类,而不是堆上分配
7.协程会消耗少量内存,直到调用yield,避免产生太多短信时间的协成
8.闭包很危险,匿名方法和lambda表达式可以是闭包,但不能总是闭包,取决于方法是否使用了它的作用于和参数列表之外的数据
9..net库要少用,比如lINQ和Rehhex类,因为 通用必定减低性能
10.对象池,预制池
TestStruct[] dataObj = new TestStruct[1000];for(int i = 0; i < 1000; ++i) { dataObj[i].data = i; DoSomething(dataObj[i]);}However, the following, functionally equivalent, code would not result in any heapallocations since the struct objects being used are value types, and hence, it would becreated on the stack:for(int i = 0; i < 1000; ++i) { TestStruct dataObj = new TestStruct(); dataObj.data = i; DoSomething(dataObj);} void TestFunction() { string testString = "Hello"; DoSomething(testString); Console.WriteLine(testString); //Debug.Log(testString);}void DoSomething(string localString) { localString = "World!";} TestFunction();这个代码还是打印hello