.NET Windows服务记录网络数据包时内存泄漏

.NET Windows服务记录网络数据包时内存泄漏,.net,vb.net,postgresql,memory-leaks,.net,Vb.net,Postgresql,Memory Leaks,我使用NDIS LWF记录来自网络的数据包。驱动程序将数据包发送到DLL,然后DLL将数据传递到.NET服务。然后,服务对数据进行一些处理,并将其转储到Postgres数据库。我在Windows服务中经历了一次内存泄漏(我想),时间似乎是随机的。正常工作时,服务的平均CPU使用率约为3%,而内存在15000-20000k之间相当稳定。由于一个尚未确定的原因,CPU将跳到25%并保持不变,而内存将增加到系统总可用内存的95%左右。因此,还有一些实现细节。在服务中,当DLL调用.NET服务时,我将数

我使用NDIS LWF记录来自网络的数据包。驱动程序将数据包发送到DLL,然后DLL将数据传递到.NET服务。然后,服务对数据进行一些处理,并将其转储到Postgres数据库。我在Windows服务中经历了一次内存泄漏(我想),时间似乎是随机的。正常工作时,服务的平均CPU使用率约为3%,而内存在15000-20000k之间相当稳定。由于一个尚未确定的原因,CPU将跳到25%并保持不变,而内存将增加到系统总可用内存的95%左右。因此,还有一些实现细节。在服务中,当DLL调用.NET服务时,我将数据复制到类对象中的字节数组中。然后,我将这个对象添加到ConcurrentQueue并发出事件信号。缩写代码为:

'rawDataIntPtr is an unmanaged BYTE* coming from the C DLL which is then freed once this callback returns

ReDim pkt.data(dataLen)
Marshal.Copy(rawDataIntPtr, pkt.data, 0, dataLen)
gLfq.Enqueue(pkt)
gLfqItemAdded.Set()
一个单独的线程用于响应新数据并从队列中取出数据。如上所述,它执行一些处理,然后通过调用ExecuteOnQueryAsync()将数据包信息添加到Postgres数据库。以下是我的消费者线程的相关代码部分:

wh(0) = gShutdownEvent
wh(1) = gLfqItemAdded
While (True)
    whRet = WaitHandle.WaitAny(wh)
    If whRet = 0 Then
        Exit While
    End If

    Try
        glfqItemAdded.Reset()
    Catch ex As Exception
        LogError()
    End Try

    While gLfq.TryDequeue(pkt)

        'Do Stuff Here

        query = "INSERT TO DATABASE"
        ExecuteNonQueryWrapperAsync()

        'I've tried the various things to try and clear
        'all references to the byte array and packet object
        'thinking this was my problem
        ReDim pkt.data(0)
        pkt.data = Nothing
        pkt = Nothing
    End While
End While

我试过SciTech的.NET Memory Profiler 5.0,它显示,当CPU和内存出现峰值时,当前分配了大量字节数组,这是有意义的。但单凭这一点并不是很有用,也不是世界上最容易理解的工具。我想,如果是内存泄漏,我会看到内存使用率缓慢增加,但事实并非如此。所以我的问题可能不是内存泄漏,而是一个组件在处理过程中落后,导致数据积压。但我不明白为什么它会在一段时间内正常工作,然后突然突然出现峰值并失去正常。网络使用也相当一致,所以我不认为这与流量峰值有关。如果需要更多代码或其他详细信息,请告诉我。如果我的设计搞砸了,我也想听听。谢谢。

另外,我意识到.NET 4的ConcurrentQueue类中有一个设计决策,有些人将其解释为内存泄漏,但我使用的是.NET 4.5.1,因此这不是一个因素。请尝试创建一个实现IDisposable的类。这个类对象将处理您的工作,但在完成工作后,它将为您提供一种保持对象状态的方法。看看这是否有帮助。谢谢你的建议,但是这个类只使用托管类型,所以我认为IDisposable没有什么价值。听起来字节数组可能被钉住了——这就是使用托管内存与本机代码交互时发生的情况;由于您使用的是异步API,很可能永远无法压缩托管堆—我们在.NET套接字服务器上遇到了这个问题。通过使用CLR Profiler和查看堆内存布局,您可以很容易地看到情况是否如此-如果是固定句柄,您可能会有大量小堆,每个堆都严重碎片化(对于高负载异步重代码,碎片率很容易达到95%)。谢谢。我现在正在运行CLR分析器来检查它。除了将所有处理和数据库代码移到DLL中,还有其他解决方案吗?