就在最近,我的几个同事帮助缩小了内存泄漏的范围。在微软的代码中发现了其中一个问题。这是来自反射器,表明枚举器会泄漏。
这里 count 属性调用 getenumerator 但从不检查 Idisposable:
public int Count
{
get
{
if (this.isDisposed)
{
throw new ObjectDisposedException(name);
}
int num = 0;
IEnumerator enumerator = this.GetEnumerator();
while (enumerator.MoveNext())
{
num++;
}
return num;
}
}
这是 ManagementObjectCollection 的 GetEnumerator,只是为了显示返回的类型是 ManagementObjectEnumerator。
public ManagementObjectEnumerator GetEnumerator()
{
if (this.isDisposed)
{
throw new ObjectDisposedException(name);
}
if (!this.options.Rewindable)
{
return new ManagementObjectEnumerator(this, this.enumWbem);
}
IEnumWbemClassObject ppEnum = null;
int errorCode = 0;
try
{
errorCode = this.scope.GetSecuredIEnumWbemClassObjectHandler(this.enumWbem).Clone_(ref ppEnum);
if ((errorCode & 0x80000000L) == 0L)
{
errorCode = this.scope.GetSecuredIEnumWbemClassObjectHandler(ppEnum).Reset_();
}
}
catch (COMException exception)
{
ManagementException.ThrowWithExtendedInfo(exception);
}
if ((errorCode & 0xfffff000L) == 0x80041000L)
{
ManagementException.ThrowWithExtendedInfo((ManagementStatus) errorCode);
}
else if ((errorCode & 0x80000000L) != 0L)
{
Marshal.ThrowExceptionForHR(errorCode);
}
return new ManagementObjectEnumerator(this, ppEnum);
}
这表明它是一次性的:
public class ManagementObjectEnumerator : IEnumerator, IDisposable
{
// Fields
private bool atEndOfCollection;
private uint cachedCount;
private IWbemClassObjectFreeThreaded[] cachedObjects;
private int cacheIndex;
private ManagementObjectCollection collectionObject;
private IEnumWbemClassObject enumWbem;
private bool isDisposed;
private static readonly string name;
// Methods
static ManagementObjectEnumerator();
internal ManagementObjectEnumerator(ManagementObjectCollection collectionObject, IEnumWbemClassObject enumWbem);
public void Dispose();
protected override void Finalize();
public bool MoveNext();
public void Reset();
// Properties
public ManagementBaseObject Current { get; }
object IEnumerator.Current { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; }
}
尽管 foreach 语句 (http://msdn.microsoft.com/en-us/library/aa664754(v=vs.71).aspx) 正确处理了一次性枚举数,但这并不意味着唯一的情况是枚举器将在 foreach 循环中使用。
我知道您可以跳过 count 属性并通过自己使用枚举器来滚动自己的机制来获取集合中的对象数量,但我的问题是这个泄漏了多少非托管内存?