[英]Microsoft.Web.Administration memory leak
具有Windows服務,該服務除其他外,可監視IIS應用程序池。 如果任何池已配置了應用程序且未運行,則將啟動該池(池)。 一段時間以來,它一直運行良好。 最近發現該服務正在泄漏內存。 查看內存轉儲的罪魁禍首是用於檢查應用程序池的Microsoft.Web.Administration。 唯一可拋棄的對象是ServerManager,我在using塊中擁有它。 已經找到有關此泄漏的其他報告,但尚未解決。 (請參閱http://msdn.microsoft.com/zh-cn/library/microsoft.web.administration.servermanager(v=vs.90).aspx#CommunityContent中的用戶注釋)
轉儲Microsoft.Web.Administration.ServerManager的所有根(此轉儲中為481)時,我只能看到其中一個根。 假設這是當前迭代。
不知道為什么這些Web.Administration對象不能被收集,即使它們似乎沒有被植根(?)。 關於如何解決此泄漏的任何想法?
我將代碼移至控制台應用程序,並在此復制了泄漏。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.Web.Administration;
namespace Web.Administration.LeakExample
{
public static class ServerManagerExtensions
{
/// <summary>
/// Returns the application counts for application pools under the specified ServerManager.
/// Application pools without applications will not be returned.
/// </summary>
/// <param name="manager"></param>
/// <returns></returns>
public static Dictionary<string, uint> GetPoolApplicationCounts(this ServerManager manager)
{
if (manager == null)
{
throw new ArgumentNullException();
}
var appCounts = new Dictionary<string, uint>(manager.ApplicationPools.Count);
foreach (var app in manager.Sites.SelectMany(site => site.Applications))
{
if (!appCounts.ContainsKey(app.ApplicationPoolName))
{
appCounts.Add(app.ApplicationPoolName, 1);
}
else
{
appCounts[app.ApplicationPoolName]++;
}
}
return appCounts;
}
}
class Program
{
static void Main(string[] args)
{
while (!Console.KeyAvailable)
{
Console.WriteLine("Checking App Pools...");
using (var manager = new ServerManager())
{
var appCounts = manager.GetPoolApplicationCounts();
var appPools = manager.ApplicationPools.Where(pool => appCounts.ContainsKey(pool.Name));
foreach (
var pool in
appPools.Where(
pool => (pool.State != ObjectState.Started) && (pool.State != ObjectState.Starting)))
{
var state = pool.Start();
if ((state == ObjectState.Started) || (state == ObjectState.Starting))
{
Console.WriteLine("Started app pool \"{0}\"", pool.Name);
}
else
{
Console.WriteLine("Failed to start app pool \"{0}\". state:{1}", pool.Name, state);
}
}
}
Console.WriteLine("Sleeping...");
Thread.Sleep(1000);
}
}
}
}
WinDbg會話:
> !dumpheap -stat
606b778c 479 5748 System.Runtime.Remoting.Activation.ConstructionLevelActivator
00472088 480 5760 System.Collections.Generic.Dictionary`2+ValueCollection[[System.String, mscorlib],[Microsoft.Web.Administration.Interop.IAppHostElement, Microsoft.Web.Administration]]
00471d5c 480 5760 System.Collections.Generic.SortedList`2+ValueList[[System.String, mscorlib],[Microsoft.Web.Administration.Configuration, Microsoft.Web.Administration]]
00194568 481 5772 Web.Administration.LeakExample.Program+<>c__DisplayClass3
00198438 480 7680 Microsoft.Web.Administration.Interop.AppHostWritableAdminManager
0047199c 481 7696 System.Linq.Enumerable+<>c__DisplayClassf`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
606cc200 958 11496 System.Char
00471e2c 479 11496 System.Collections.Generic.SortedList`2+SortedListValueEnumerator[[System.String, mscorlib],[Microsoft.Web.Administration.Configuration, Microsoft.Web.Administration]]
0047090c 479 11496 System.Collections.Generic.List`1+Enumerator[[Microsoft.Web.Administration.Site, Microsoft.Web.Administration]]
004706f0 958 11496 Microsoft.Web.Administration.ConfigurationElementCollectionBase`1+<>c__DisplayClass4[[Microsoft.Web.Administration.Site, Microsoft.Web.Administration]]
00471aec 480 11520 System.Collections.Generic.List`1+Enumerator[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
0047041c 480 11520 System.Collections.Generic.List`1[[Microsoft.Web.Administration.Site, Microsoft.Web.Administration]]
00196d58 480 11520 System.Collections.Generic.List`1[[Microsoft.Web.Administration.Configuration, Microsoft.Web.Administration]]
004715cc 481 11544 System.Collections.Generic.List`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
0047103c 1437 17244 Microsoft.Web.Administration.ConfigurationElementCollectionBase`1+<>c__DisplayClass4[[Microsoft.Web.Administration.Application, Microsoft.Web.Administration]]
606ccfc8 1438 17256 System.Int32
00196a58 480 19200 System.Collections.Generic.SortedList`2[[System.String, mscorlib],[Microsoft.Web.Administration.Configuration, Microsoft.Web.Administration]]
0019660c 480 21120 Microsoft.Web.Administration.ConfigurationManager
00471130 958 22992 System.Collections.Generic.List`1+Enumerator[[Microsoft.Web.Administration.Application, Microsoft.Web.Administration]]
00470d68 960 23040 System.Collections.Generic.List`1[[Microsoft.Web.Administration.Application, Microsoft.Web.Administration]]
00198558 480 23040 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[Microsoft.Web.Administration.Interop.IAppHostElement, Microsoft.Web.Administration]]
00196a08 481 23088 Microsoft.Web.Administration.Configuration
00183170 481 23088 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.UInt32, mscorlib]]
606b7574 479 24908 System.Runtime.Remoting.Messaging.ConstructorCallMessage
00199e7c 479 24908 System.Linq.Enumerable+<SelectManyIterator>d__14`2[[Microsoft.Web.Administration.Site, Microsoft.Web.Administration],[Microsoft.Web.Administration.Application, Microsoft.Web.Administration]]
00199384 480 28800 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[Microsoft.Web.Administration.Interop.IAppHostElement, Microsoft.Web.Administration]][]
00470874 958 30656 System.Predicate`1[[Microsoft.Web.Administration.Site, Microsoft.Web.Administration]]
004718a8 962 30784 System.Linq.Enumerable+WhereEnumerableIterator`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
001944d8 481 30784 Microsoft.Web.Administration.ServerManager
00195178 963 30816 System.Func`2[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration],[System.Boolean, mscorlib]]
606ccf90 968 31268 System.Int32[]
00197a50 480 32640 Microsoft.Web.Administration.SiteCollection
00194da0 481 32708 Microsoft.Web.Administration.ApplicationPoolCollection
004719f8 2874 34488 Microsoft.Web.Administration.ConfigurationElementCollectionBase`1+<>c__DisplayClass4[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
0019810c 960 42240 Microsoft.Web.Administration.ConfigurationSection
00471098 1437 45984 System.Predicate`1[[Microsoft.Web.Administration.Application, Microsoft.Web.Administration]]
606cc1c8 961 46638 System.Char[]
001838d0 481 59644 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.UInt32, mscorlib]][]
606bedd0 5269 63228 System.UInt32
00470a7c 960 69120 Microsoft.Web.Administration.ApplicationCollection
00197c60 960 76800 Microsoft.Web.Administration.Site
00197ea8 1440 86400 Microsoft.Web.Administration.Application
00471a54 2874 91968 System.Predicate`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
6067c684 4832 141272 System.Object[]
00195024 2886 196248 Microsoft.Web.Administration.ApplicationPool
606c7b20 16323 261168 System.__ComObject
>.foreach (obj {!dumpheap -mt 001944d8 -short}){!gcroot -all obj}
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+70: 002ef148
-> 02773270 System.Linq.Enumerable+WhereEnumerableIterator`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
-> 02772948 Microsoft.Web.Administration.ApplicationPoolCollection
-> 02772060 Microsoft.Web.Administration.ServerManager
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+68: 002ef150
-> 02773270 System.Linq.Enumerable+WhereEnumerableIterator`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
-> 02772948 Microsoft.Web.Administration.ApplicationPoolCollection
-> 02772060 Microsoft.Web.Administration.ServerManager
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+78: 002ef140
-> 027732c0 System.Linq.Enumerable+WhereEnumerableIterator`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
-> 02772948 Microsoft.Web.Administration.ApplicationPoolCollection
-> 02772060 Microsoft.Web.Administration.ServerManager
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+6c: 002ef14c
-> 02773270 System.Linq.Enumerable+WhereEnumerableIterator`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
-> 02772948 Microsoft.Web.Administration.ApplicationPoolCollection
-> 02772060 Microsoft.Web.Administration.ServerManager
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+74: 002ef144
-> 027732c0 System.Linq.Enumerable+WhereEnumerableIterator`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
-> 02772948 Microsoft.Web.Administration.ApplicationPoolCollection
-> 02772060 Microsoft.Web.Administration.ServerManager
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+60: 002ef158
-> 02772948 Microsoft.Web.Administration.ApplicationPoolCollection
-> 02772060 Microsoft.Web.Administration.ServerManager
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+3c: 002ef17c
-> 02772060 Microsoft.Web.Administration.ServerManager
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+4c: 002ef16c
-> 027732c0 System.Linq.Enumerable+WhereEnumerableIterator`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
-> 02772948 Microsoft.Web.Administration.ApplicationPoolCollection
-> 02772060 Microsoft.Web.Administration.ServerManager
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+40: 002ef178
-> 02773270 System.Linq.Enumerable+WhereEnumerableIterator`1[[Microsoft.Web.Administration.ApplicationPool, Microsoft.Web.Administration]]
-> 02772948 Microsoft.Web.Administration.ApplicationPoolCollection
-> 02772060 Microsoft.Web.Administration.ServerManager
002ef124 003f0359 Web.Administration.LeakExample.Program.Main(System.String[]) [c:\Users\Chuck\Documents\Visual Studio 2012\Projects\Web.Administration.LeakExample\Web.Administration.LeakExample\Program.cs @ 74]
ebp+50: 002ef168
-> 02772060 Microsoft.Web.Administration.ServerManager
Found 10 roots.
當我第一次閱讀該問題時,我想到的第一件事是,可以通過使用Windows激活服務(WAS)完全避免整個問題。
我對您發布的代碼的第一次了解使我感到您的問題可能與訪問/修改由foreach
循環創建的各種閉包有關。
嘗試這些小的重構,看看是否有任何/全部能夠減少或消除問題或失敗的方法,從而提供了更多有關根本原因的信息:
.ToList()
避免延遲執行LINQ查詢 ServerManager
對象,而是在循環的每次迭代中創建一個新對象 由於您僅使用ApplicationPool.Name
,因此請重構:
foreach (var app in manager.Sites.SelectMany(site => site.Applications))
對此:
foreach (var app in manager.Sites.SelectMany(site => site.Applications,
(s, a) => a.Name)
.ToList())
我的假設是正在發生的事情:
using
語句中創建ServerManager
新實例 ApplicationPools
ApplicationPools
,該IQueryable會立即使用(但不會完全執行foreach
語句在內部使用yield return
)並進行過濾。 .Start()
更改(突變) ServerManager
對象引用所引用的ApplicationPool
狀態 ServerManager
。 由於該引用具有突變狀態(由於調用.Start()
),因此它可能已被GC標記並且從未被收集-該應用程序池從不返回后續迭代的結果,並且可能導致該引用的孤立記憶。 請記住,這只是一個假設!
我現在認為這不是真正的泄漏。 我嘗試按照Josh的建議對所有內容進行ToList()處理。 這不會影響內存使用。
我將GC.Collect()添加到循環中(僅用於測試目的),從而消除了“泄漏”。 我通過進行內存轉儲來驗證這一點,如果我在堆上沒有找到Web.Application對象。 這與我以前的轉儲中看到的所有Web.Application對象實際上都植根這一事實相吻合。 其他人沒有扎根,等待被收集。
.NET垃圾收集器的不確定性使我大跌眼鏡。 對不起,噪音。
我在這里找到了解決方案: www.tomanderson.me 。
建議使用
using (ServerManager sm = ServerManager.OpenRemote("localhost"))
{ /*..*/ }
對我有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.