这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
引言
在上古年代,C/C++ 是需要程序员手动释放内存的。而C#为了解决堆内存释放问题与手动管理内存时的心智负担及人为管理不当时可能出现的Bug,引入了GC(垃圾回收)。但是,当应用程序的GC出现了回收压力,尤其是对 大对象堆
的分配和释放。应用程序性能会降低。今天,我们来学习一下如何缓解GC压力
使用Struct
来看一段代码:
public struct BinaryTree
{
public int Left { get; set; }
public int Right { get; set; }
}
public class BinaryTreeReference
{
public int Left { get; set; }
public int Right { get; set; }
}
[BenchmarkDotNet.Attributes.MemoryDiagnoser]
public class Program
{
[Benchmark]
public void AllocationStruct()
{
List<BinaryTree> binaryTrees = new List<BinaryTree>(10000);
for (int i = 0; i < 10000; i++)
{
binaryTrees.Add(new BinaryTree
{
Left = i,
Right = i
});
}
}
[Benchmark]
public void AllocationClass()
{
List<BinaryTreeReference> binaryTrees = new List<BinaryTreeReference>(10000);
for (int i = 0; i < 10000; i++)
{
binaryTrees.Add(new BinaryTreeReference
{
Left = i,
Right = i
});
}
}
static void Main(string[] args)
{
BenchmarkRunner.Run<Program>();
}
}
复制代码
上面代码我们就是做了一个简单分配,我们声明了 structBinaryTree 和 ClassBinaryTreeReference。然后循环1000次将他们添加到List中
struct是【值类型】,List里面只会存储它的一整块内存,而class是 【引用类型】。List在存储它的时候会先分配10000个对象,并将这些对象的引用存储在数组中。这比struct繁琐了许多
下面是基准测试的结果:
上面测试中也可以看到,AllocationStruct方法快了将近5倍,同时也减少了内存分配(仅78 KB)。减少了GC压力
何时使用struct?
struct是值类型,
看过上面的测试后,有些朋友可能要问了鸭,struct这么强。我以后就不用class啦 OH NO!!!
请看下面关于何时使用 strcut的建议:
- 当你的存储的类型字段较少时,应该使用strcut
- 这个变量存活周期较长时,我们应该使用class 例如:该变量需要在多个方法传递
- 当需要存储几千个以上的对象时,应该使用class
- 需要存储引用而不是strcut时(因为struct在传给其他方法时,会产生值复制),这时应该使用class
减少装箱操作
尽量减少将值类型强制转换为引用类型,例如:
刚刚创建的BinaryTree是值类型,而Console.WriteLine() 的第二个参数的类型是object。对于此类问题,我们通常使用泛型来解决(后面有空再写写~)。
总结
为了减少GC的运行次数,减轻程序压力。总结以下几点进行优化:
- 尽量使可以重用的对象可以重用,例如:使用单例
- 生命周期较短的变量可以用strcut来替代class
- 尽量避免大对象的分配
- 使用对象池
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END