本文主要探讨关于C#中对值类型的List.Remove操作的GC问题。
一、先说结论:
1、【🔴】纯结构体,啥都不做,gc很多。
2、【🔴】结构体实现IComparable接口的CompareTo(Struct2 other) ,无法优化掉gc。
3、【🟢】结构体实现IEquatable接口的Equals(Struct3 other),gc为0。
4、【🟣】结构体实现IEquatable接口和IComparable接口,gc为0(由234可以得出,只要实现IEquatable接口即可优化掉gc)
5、【🟣】结构体重写Equals(object other)方法,少量gc(存在装箱)
6、【🔴】结构体只重写==和!=操作符的结果跟1一样。
二、执行以下方法查看gc情况:
List<Struct1> list1 = new List<Struct1>();
List<Struct2> list2 = new List<Struct2>();
List<Struct3> list3 = new List<Struct3>();
List<Struct4> list4 = new List<Struct4>();
List<Struct5> list5 = new List<Struct5>();
// X代表12345
void UpdateX()
{
for (int i = 0; i < 100; i++)
{
listX.Add(new StructX());
}
for (int i = 0; i < listX.Count; i++)
{
listX.Remove(listX[0]);
}
}
三、结果:
四、具体实现
// 啥都不做 100次remove gc 15.6kb
struct Struct1
{
public int num;
public bool isUsed;
}
// 实现IComparable接口 100次remove gc 15.6kb
struct Struct2 : IComparable<Struct2>
{
public int num;
public bool isUsed;
int IComparable<Struct2>.CompareTo(Struct2 other)
{
return this.num - other.num;
}
}
// 实现IEquatable接口 100次remove gc 0kb
struct Struct3 : IEquatable<Struct3>
{
public int num;
public bool isUsed;
bool IEquatable<Struct3>.Equals(Struct3 other)
{
return this.num == other.num;
}
}
// 实现IEquatable接口和IComparable接口 100次remove gc 0kb (从这里可以得出,只要实现IEquatable接口即可优化掉gc)
struct Struct4 : IComparable<Struct4>, IEquatable<Struct4>
{
public int num;
public bool isUsed;
int IComparable<Struct4>.CompareTo(Struct4 other)
{
return this.num - other.num;
}
bool IEquatable<Struct4>.Equals(Struct4 other)
{
return this.num == other.num;
}
}
// 重写Equals方法 100次remove gc 3.1kb(装箱)
struct Struct5
{
public int num;
public bool isUsed;
public override bool Equals(object obj)
{
return obj is Struct5 t &&
num == t.num;
}
}