C#使用List.Clear()方法可以让GC回收内存吗?
2018-03-08 16:47
1021 查看
问题:我现在有一个list,里面放了若干对象,因为业务需要,程序运行后根据用户需求,要把list清空,再装入新的东西,每一次用之前都会清空它,然后装入新的东西,请问,内存是否会泄漏?测试:我设计一个list,清空用clear方法,装入新东西用add(new obj)。
使用按键调用这个方法,每一次调用循环10w次。
通过任务管理器查看内存状态。刚打开app:
按下一次按键,运行10w次
多次按下按键,实验次数大于10次
实验结果表明,C#的GC对于本案例有较好的内存控制,第一次运行之后有内存上升,之后内存消耗非常稳定。分析,本例中,list中添加的对象为Card,每一次添加Card都是通过new的方法创建一个新的Card。Clear只是清空了list中对于这个Card对象的引用,并没有对每一张Card本身引用做null,但是,根据GC的官方信息,有两方面,1、每一张new出来的card只有list可以引用,clear之后,引用计数变为0,认为是垃圾。2、每一张new出来的card从list中移除后,从程序的数据树根就无法再次通过直接“爬树”的方法访问到,成为了程序数据树中不存在,但是总数据等级表中存在的东西(new一次GC会额外做一次登记),这样就会被认为是垃圾。
新的问题来了,我这个算法中有一个洗牌算法,洗牌算法原理参照我的上一篇blog
洗牌算法-Fisher–Yates算法为什么好?
这个洗牌算法代码如下:public static void Shuffle(List<short> list)
{
int length = list.Count;
short tmp, rdtmp;
Random rd = new Random();
for (int i = 0; i < length; i++)
{
rdtmp = (short)rd.Next(i, length);
//Console.WriteLine(i + ": " + rdtmp + " ");
tmp = list[rdtmp];
list[rdtmp] = list[i];
list[i] = tmp;
}
//rd = null;
} 这个里面有一个问题,每一次运行洗牌算法都需要一个random对象
Random rd = new Random();运行10w次就是new了10w次,从上面的内存分析可以看出,这个也被很好的控制了。
具体分析为,每一次new都生成了一个对象,然后每一次运行这段程序,rd都在不断的指向新的random对象,之前的random对象都变成了野的对象,因此,GC也能通过上述的两种方法发现老的random对象,实现回收,所以最后的
//rd = null;我直接注释掉了,因为不需要。
所以,放心的new吧。不用管内存回收的事情。
爽!
public void GameInit() { PlayerCnt = 0; PlayerList.Clear(); PileCnt = 0; Pile.Clear(); DisPileCnt = 0; DisPile.Clear(); } public void GameStrat() { GameInit(); //准备新牌堆,洗牌 PileCnt = Card.DeckLength; List<short> sort = new List<short>(); for (short i = 0; i < PileCnt; i++) { sort.Add(i);//0-207 } Shuffle(sort); for (short i = 0; i < PileCnt; i++) { Pile.Add(new Card(Card.Deck[sort[i]])); } }
使用按键调用这个方法,每一次调用循环10w次。
//menu-操作-重启游戏 的 事件 private void Menu_Restart_click(object sender, RoutedEventArgs e) { int i = 0; for (; i < 100000; i++) { GameInst.GameStrat(); } Console.WriteLine("Debug"+i); }
通过任务管理器查看内存状态。刚打开app:
按下一次按键,运行10w次
多次按下按键,实验次数大于10次
实验结果表明,C#的GC对于本案例有较好的内存控制,第一次运行之后有内存上升,之后内存消耗非常稳定。分析,本例中,list中添加的对象为Card,每一次添加Card都是通过new的方法创建一个新的Card。Clear只是清空了list中对于这个Card对象的引用,并没有对每一张Card本身引用做null,但是,根据GC的官方信息,有两方面,1、每一张new出来的card只有list可以引用,clear之后,引用计数变为0,认为是垃圾。2、每一张new出来的card从list中移除后,从程序的数据树根就无法再次通过直接“爬树”的方法访问到,成为了程序数据树中不存在,但是总数据等级表中存在的东西(new一次GC会额外做一次登记),这样就会被认为是垃圾。
新的问题来了,我这个算法中有一个洗牌算法,洗牌算法原理参照我的上一篇blog
洗牌算法-Fisher–Yates算法为什么好?
这个洗牌算法代码如下:public static void Shuffle(List<short> list)
{
int length = list.Count;
short tmp, rdtmp;
Random rd = new Random();
for (int i = 0; i < length; i++)
{
rdtmp = (short)rd.Next(i, length);
//Console.WriteLine(i + ": " + rdtmp + " ");
tmp = list[rdtmp];
list[rdtmp] = list[i];
list[i] = tmp;
}
//rd = null;
} 这个里面有一个问题,每一次运行洗牌算法都需要一个random对象
Random rd = new Random();运行10w次就是new了10w次,从上面的内存分析可以看出,这个也被很好的控制了。
具体分析为,每一次new都生成了一个对象,然后每一次运行这段程序,rd都在不断的指向新的random对象,之前的random对象都变成了野的对象,因此,GC也能通过上述的两种方法发现老的random对象,实现回收,所以最后的
//rd = null;我直接注释掉了,因为不需要。
所以,放心的new吧。不用管内存回收的事情。
爽!
相关文章推荐
- NET C# List泛型集合 使用方法
- 浅谈C#内存回收与Dispose﹐Close﹐Finalize方法
- NET C# List泛型集合 使用方法
- The NOTE of learning ASP.NET [19] 关于GC(内存回收机制)、对象的销毁和using的使用
- Python中list的append方法添加,和使用下标取得。之中的元素还可以是其他的数据结构
- 浅谈C#内存回收与Dispose﹐Close﹐Finalize方法[转]
- C#内存回收与Dispose﹐Close﹐Finalize方法
- C#中List的Find方法的使用
- [C#]List的Sort()、Find()、FindAll()、Exist()的使用方法举例
- C#中使用repeater控件实现List的clear,add,update,delete功能之二数据库
- C#用什么方法可以减少或不使用switch
- C#开发里List控件的使用方法介绍
- C#中List的Find方法的使用
- [C#/ASP.NET]List<>中Sort()、Find()、FindAll()、Exist()的使用方法
- 可以在Silverlight中使用的,支持定时自动回收的缓存类(C# 代码)
- C#小练习(使用方法重载使得方法可以分别计算整数、双精度、字符串)
- 线谈C#内存回收与Dispose﹐Close﹐Finalize方法
- GC 回收WPF 内存 C#通用
- 浅谈C#内存回收与Dispose﹐Close﹐Finalize方法[转]
- C#范型List的一些方法的使用