Which objects survive on the managed heap.
Who is holding on to objects.
What the garbage collector does over the lifetime of your application.

得到這些信息以后就決定使用一下,讓服務(wù)端運(yùn)行了一會(huì)兒,停止以后得到分析結(jié)果,最終在Allocation Graph視圖下了解到原來(lái)是下載文件DownloadFile方法下的byte[]數(shù)組引起的,短短不到一分鐘的時(shí)間竟然占用了兩百多兆的內(nèi)存,好了,這下可找到“原兇”了,有得折騰了

方案1:把要下載的數(shù)據(jù)一并加載到內(nèi)存,用戶在下載的時(shí)候通過(guò)position來(lái)獲取byte[]不新建直接返回,是能解決問(wèn)題,但這就大大降低了服務(wù)端的可用性啊,只能當(dāng)做小文件服務(wù)端,太不合理。

方案2:由于下載文件的時(shí)候返回的是一個(gè)可序列化的類,所以想是不是這里出現(xiàn)了問(wèn)題,可以直接返回 byte[],以最基本的數(shù)據(jù)頭->數(shù)據(jù)長(zhǎng)度->數(shù)據(jù)->數(shù)據(jù)尾來(lái)實(shí)現(xiàn),但這樣一來(lái)要改的東西太多了,服務(wù)端客戶端,協(xié)議重構(gòu),眼看著就要落幕的項(xiàng)目卻要重頭再來(lái)心有不甘那,再加上還有一堆任務(wù)在后面趕著,這不是坑自己?jiǎn)幔卜艞壛恕?/p>

然后又回到各種網(wǎng)絡(luò)資料搜索上,經(jīng)過(guò)一番查找后了解到,byte[]最終也是會(huì)被回收的,只要是托管的數(shù)據(jù)都是能被回收的,只是周期可能會(huì)長(zhǎng)一些,最后又回到了Remoting本身上,抱著試一試的心態(tài)把WellKnowObjectMode由SingleTon改為了SingleCall,跑了一晚上最后穩(wěn)定在了200M上下,總算松了口氣。

使用SingleTon本來(lái)是想節(jié)省內(nèi)存消耗的,可沒(méi)想到得不償失如此的大費(fèi)周折,遂總結(jié)出SingleTon并不適合并發(fā)量大的服務(wù)端程序,SingleTon是單線程模式,在調(diào)用每個(gè)方法的時(shí)候都會(huì)被加鎖,猜測(cè)造成數(shù)據(jù)一直不能被釋放的原因是由這些鎖造成的,由于連接的數(shù)量太多導(dǎo)致連接一直處于排隊(duì)狀態(tài),造成了后面連接的客戶端響應(yīng)過(guò)慢,連接超時(shí),在這里也給大家一個(gè)教訓(xùn)還是用SingleCall實(shí)在。

上面說(shuō)了這么多只是跟大家分享一下解決問(wèn)題的經(jīng)驗(yàn),還有敘述了一下問(wèn)題的所在,如果各位有不同的見(jiàn)解請(qǐng)一定要指出來(lái),畢竟.NET內(nèi)存分配、垃圾回收本就比較復(fù)雜。

然事與愿違卻柳暗花明

這篇文章的重點(diǎn)是講如何使用CLRProfiler來(lái)查找.NET程序的內(nèi)存分配情況的,下面就開(kāi)始吧。

下載CLR Profiler:http://search.microsoft.com/en-us/DownloadResults.aspx?q=clr%20profiler

可根據(jù)自己.NET的版本下載相應(yīng)的CLRProfiler,下面以.NET4.0版本為例。CLRProfiler可以分析應(yīng)用程序,服務(wù)和ASP.NET編寫的程序,以下以應(yīng)用程序?yàn)槔秊榇蠹已菔救绾魏?jiǎn)單使用CLRProfiler。

下面是一個(gè)拆箱裝箱的例子CLRProfilerTestDemo,通過(guò)這個(gè)例子來(lái)觀察進(jìn)程托管堆的分配和研究垃圾回收機(jī)制的行為表現(xiàn),代碼如下

using System; using System.Collections.Generic; namespace CLRProfilerTestDemo { class Program { static void Main(string[] args) { for (int i = 0; i < 100 * 1000; i++) { Boxing box = new Boxing(); } Environment.Exit(Environment.ExitCode); } } class Boxing { private List box = new List(); private List unbox = new List(); public Boxing() { for (int i = 0; i < 1000; i++) { box.Add(i); unbox.Add((int)box[i]); } } } }

運(yùn)行CLRProfiler,選中Allocation和Calls選項(xiàng)如下圖:

編譯程序,點(diǎn)擊Start Application選擇CLRProfilerTestDemo.exe,將會(huì)運(yùn)行此程序,運(yùn)行一段時(shí)間后,點(diǎn)擊Kill Application,CLRProfiler將會(huì)顯示分析結(jié)果。

打開(kāi)Allocated bytes直方圖界面,如下圖,在右側(cè)的分配類型區(qū)可以找到可疑的類Boxing

下面是Allocation Graph內(nèi)存分配視圖,在這個(gè)視圖當(dāng)中我們可以看出堆棧是如何分別對(duì)象的。

通過(guò)CLRProfiler工具進(jìn)行這幾步簡(jiǎn)單的操作即可找出造成應(yīng)用程序內(nèi)存飆升的源頭,并想辦法修復(fù),很簡(jiǎn)單吧,如果感興趣的朋友可以去網(wǎng)上更加詳細(xì)的了解。

 

分享到

hanrui

相關(guān)推薦