| File: LeakTrackingObjectPool.cs | Web Access |
| Project: src\aspnetcore\src\ObjectPool\src\Microsoft.Extensions.ObjectPool.csproj (Microsoft.Extensions.ObjectPool) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics; using System.Runtime.CompilerServices; using Microsoft.AspNetCore.Shared; namespace Microsoft.Extensions.ObjectPool; /// <summary> /// An <see cref="ObjectPool{T}"/> implementation that detects leaks in the use of the object pool. /// <para> /// A leak is produced if an object is leased from the pool but not returned before it is finalized. /// An error is only produced in <c>Debug</c> builds. /// This type is only recommended to be used for diagnostic builds. /// </para> /// </summary> /// <typeparam name="T">The type of object which is being pooled.</typeparam> [Obsolete("LeakTrackingObjectPool<T> was only intended for internal use in diagnostic builds of .NET. " + "It never functioned in publicly shipped .NET versions and may be removed in a future release.")] public class LeakTrackingObjectPool<T> : ObjectPool<T> where T : class { private readonly ConditionalWeakTable<T, Tracker> _trackers = new ConditionalWeakTable<T, Tracker>(); private readonly ObjectPool<T> _inner; /// <summary> /// Initializes a new instance of <see cref="LeakTrackingObjectPool{T}"/>. /// </summary> /// <param name="inner">The <see cref="ObjectPool{T}"/> instance to track leaks in.</param> public LeakTrackingObjectPool(ObjectPool<T> inner) { ArgumentNullThrowHelper.ThrowIfNull(inner); _inner = inner; } /// <inheritdoc/> public override T Get() { var value = _inner.Get(); _trackers.Add(value, new Tracker()); return value; } /// <inheritdoc/> public override void Return(T obj) { if (_trackers.TryGetValue(obj, out var tracker)) { _trackers.Remove(obj); tracker.Dispose(); } _inner.Return(obj); } private sealed class Tracker : IDisposable { private readonly string _stack; private bool _disposed; public Tracker() { _stack = Environment.StackTrace; } public void Dispose() { _disposed = true; GC.SuppressFinalize(this); } ~Tracker() { if (!_disposed && !Environment.HasShutdownStarted) { Debug.Fail($"{typeof(T).Name} was leaked. Created at: {Environment.NewLine}{_stack}"); } } } }