这垃圾收集是咋回事啊?

AgedBOY 2013-11-05 10:13:07
各位高手,本人不是懂.net framework。由于工作原因,最近要帮忙调查一个客户遇到的困难。

有一程序,32位编译生成,以约1Hz的频率调用一函数。该函数内有new byte[30MB]。但可以确认,得到的数组在函数退出后再无其他引用。

可是却观察到,随着程序运行,其内存使用量不停增长。在接近1.8G时,new产生System.OutOfMemory异常。

后实验发现,如果我用try...catch捕获该异常,并在catch里强制System.GC.collect,则内存使用量即刻下降到正常值,并程序可以继续如常运行。

我不明白的是,假如我设计.net,肯定会在new找不到足够长的连续空间时,先自动尝试GC,GC后还不行,再抛异常。换句话说,假如这样设计,则我在catch里再GC应该也没用了。

可是我遇到的现象为何是那样?

附:W2K3 32Bits .Net 4.0。谢谢。
...全文
567 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
AgedBOY 2013-11-06
  • 打赏
  • 举报
回复
AgedBOY 2013-11-06
  • 打赏
  • 举报
回复
客户的代码不方便贴出来,上午现写了一个。我不太懂C#,硬着头皮写的,高手别见笑。 但关键是,这个程序就能复现GC不干活儿的问题。 看code时请注意里面的两段注释。

using System;
using System.Threading;

namespace crazyMemory1
{
	class Program
	{
		static void Main(string[] args)
		{
			// withOUT these two lines, GC also worked almost 
			// well --- it reached >1.2GB then dropped back to 
			// hundreds MB without exception throwing.
			byte[] nop = new byte[800 * 1048576];

			Program inst = new Program();

			// go
			Thread thread = new Thread(inst.threadProc);
			thread.Start();

			// press ENTER to quit
			Console.ReadKey();

			// stop it
			inst.m_stop.Set();
			thread.Join();
		}

		private ManualResetEvent m_stop = new ManualResetEvent(false);
		private AutoResetEvent m_clock = new AutoResetEvent(false);
		private enum EVENT_INDEX { STOP, CLOCK };

		private void onTimer(object input)
		{
			m_clock.Set();
		}

		private void threadProc()
		{
			Timer timer = new Timer(onTimer, null, 0, 500);
			WaitHandle[] events = { m_stop, m_clock };

			while (true)
			{
				EVENT_INDEX wait = (EVENT_INDEX)WaitHandle.WaitAny(events, Timeout.Infinite);

				if (EVENT_INDEX.STOP == wait)
					break;
				else if (EVENT_INDEX.CLOCK == wait)
					memoryEater();
			}

			timer.Dispose();
		}

		private void memoryEater()
		{
			try
			{
				byte[] buf = new byte[30 * 1048576];

				// withOUT these two lines, GC also worked 
				// almost well --- it reached >1.9GB then 
				// dropped back to hundreds MB without exception
				// throwing.
				byte bvalue = Convert.ToByte((new Random()).Next(0, 255));
				Array.ForEach(buf, b => b=bvalue);
			}
			catch (System.Exception ex)
			{
				Console.WriteLine(ex);
				return;
			}

			Console.WriteLine("memory allocated");
		}
	}
}
jiaoshiyao 2013-11-06
  • 打赏
  • 举报
回复
这个。。以前也遇到过GC不回收的问题不过我的是图片文件的byte[]数组 个人感觉你没有用什么第三方的东西 或者C++啊 其他语言的类库 还有 你确保所有的引用都消除掉 应该不会不回收
AgedBOY 2013-11-06
  • 打赏
  • 举报
回复
另外还有一发现,假如我在程序一开始申请一个大数组,比如三四百兆,并保证它不会出scope,则原帖中现象就会非常稳定发生,好像大block会干扰gc似的。而如果没有它,也原帖现象较难发生。
AgedBOY 2013-11-06
  • 打赏
  • 举报
回复
这确实没有客观的确认方法,靠看code。但是在outofmemory异常的catch里强制gc,内存就降下来了,也侧面确认啊。
q107770540 2013-11-05
  • 打赏
  • 举报
回复
引用 楼主 AgedBOY 的回复:
但可以确认,得到的数组在函数退出后再无其他引用。
如何确认的?
threenewbee 2013-11-05
  • 打赏
  • 举报
回复
得看你的代码才知道了。按理说GC机制本身没有问题。

17,740

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 .NET Framework
社区管理员
  • .NET Framework社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧