Hit the Assert in SimpleLeakAwareByteBuffer.CloseLeak
Run the below code, and you can see an false case of leak is reported. And an Debug.Assert can be seen when run with Debug builds of DotNetty.
@nayato @StormHub Any idea for this?
I think the Retain/Release of IByteBuffer is thread-safe(just don't read/write bytebuf concurrently)?
Use the ExampleHelper from Examples.Common
internal class Program
{
static Program()
{
Environment.SetEnvironmentVariable("io.netty.leakDetection.targetRecords", "256");
DotNetty.Common.ResourceLeakDetector.Level = DotNetty.Common.ResourceLeakDetector.DetectionLevel.Paranoid;
}
private static void Main()
{
ExampleHelper.SetConsoleLogger();
{
var loop = new SingleThreadEventLoop();
int i = 0;
do
{
var buf0 = ByteBufferUtil.DefaultAllocator.Buffer();
buf0.WriteInt(i);
buf0.WriteInt(i);
++i;
loop.Schedule(state1 =>
{
var buf1 = (IByteBuffer)state1;
buf1.ReadInt();
buf1.Release();
}, buf0.RetainedSlice(), TimeSpan.FromMilliseconds(10));
buf0.Release();
buf0 = null;
Thread.Sleep(10);
}
while (true);
}
}
}
-
GCNotice.Rearm()remove itself fromgcNotificationMap, and never add it back again, which hit the assert. -
The cache of
PooledSlicedByteBuffer(or others) can be reused immediately after callbase.Release()without callCloseLeak(), which hit theGCNotice.Rearm(). The same thing also happen on netty, but the implement of netty allow to track different of the sametrackedObject, and onlyReportLeakif all reference of thetrackedObjectis gone. (So may never happen for the ones kept forever in cache) https://github.com/Azure/DotNetty/blob/6c255296e9fcd87cc8a3a81208cb29a4a19672c4/src/DotNetty.Buffers/SimpleLeakAwareByteBuffer.cs#L61-L69 -
DefaultResourceLeak.Closecallthis.owner.gcNotificationMap.Remove(trackedObject)insideDebug.Assert(), which will be stripped out in Release builds and not work. -
In fact, all method of
ConditionalWeakTable<,>it thread-safe, but usegcNotificationMap.Add/RemoveafterTryGetValuemay be not. But can not hit it when do test.
Will post an PR later.(May be with a bit more overhead for track with an LinkedList and lock in GCNotice)