我写了一个程序,单线程运行时内存非常正常,多线程运行不到半小时,内存就从80M升至900多M,经多天调试毫无进展,因为每次运行到进程内存接近1G时会报内存溢出的错误,错误语句比较随机,有时只是一个int变量分配,请问是否有办法查看是哪些资源没有释放?
求调试方法?
以下是我的代码的伪代码结构,MyTask为我自定义线程包装类,此类内部会开一个线程执行TaskProc,代码运行可能需要一个月时间,所以内存问题非常重要:
var task = new MyTask();
task.Start(null);
void TaskProc()
{
...
foreach(var p in params)
{
var innerTask = new MyTask();
innerTask.Start(p);
while(innerTask.IsRunning) //等待innerTask运行结束
Thread.Sleep(1000);
}
...
}
MyTask无递归调用,只有这两层。
首先看下你的程序中有多少个线程,本身每个线程就要占1m内存的,线程多了程序肯定挂。
至于对象的内存占用,Visual Studio自己就带memory profile工具,从分析菜单里就可以进去。也有一些第三方的memory profile工具做得不错的:http://memprofiler.com/ 。
另外,MS还提供了一个CLR Profiler,要精简得多,在不方便使用这些大型调试工具的地使用也很方便的。
我下了个,memory profile 4.6,但这个工具使用真是复杂,看了大半天,看不懂啊,我要疯了
@沧海一杰: 在内存达到1G时我抓到一个快照,共8个线程,4个alive的,我觉得也算正常。占用内存最大的字符串类型,其中最大占用空间最大的字符串实例都是指向下面这个方法:
public static string GetWebBrowserSourceCode(WebBrowser browser) { if (browser.Document == null) return string.Empty; if (browser.Document.DomDocument == null) return string.Empty; var document = (browser.Document.DomDocument as mshtml.HTMLDocumentClass); if (document != null && document.documentElement != null) return document.documentElement.outerHTML ?? string.Empty; else return string.Empty; }
这个方法有问题吗?会导致内存不被释放吗?
@沧海一杰: w从这些数据能否看出是托管泄漏还是非托管泄漏?我的程序同时应该只有两个线程运行,单线程包括UI线程占了80M,两个正常应该在200M下,但实际上最终却涨到了超过1G而导致内存溢出。
我以前也遇到你的类似问题,仅看你提供的伪代码看不出问题,你的问题无非是线程太多(可能有你未察觉的潜在线程),资源释放有问题,这类问题的解决除了经验外,需要艰苦细致的工作,成本有时会很高。可以加QQ:1561724180探讨。
大神再给出出主意吧
问题可能出在MyTask,如果方便的话,建议贴出MyTask的实现代码
贴出代码可能不太方便,一是太多,二是需要保密一部分东西。
@沧海一杰: 大神再给出出主意吧
问题已经解决,谢谢各位。原因如上面我的伪代码所定,这种结构有问题。虽然宿主线程在Sleep,但线程中有事件被UI线程订阅,其它过程仍然会导致线程内其它方法运行,导致很多资源没有释放。这种结构实际上只有一个线程在同时运行,所以改成单线程递归调用就很正常了,测试了很久,暂时没有发现内存泄漏的迹象了。