【发布时间】:2019-06-14 11:21:55
【问题描述】:
我想在我的应用程序中找到内存泄漏。 我会尝试在不安装软件或扩展程序的情况下查找泄漏。
点击此链接
我尝试建立自己的课程。
代码如下:
''' <summary>
''' Use: lanch instance of the class
''' - Friend memorytest As New MemoryLeakTest(MemoryLeakTest.memorySize.MBytes)
''' Parameters:
''' - MemorySize (MBytes, KBytes, Bytes)
''' - AlertSize (set Alert to True if the increment of the new memory usage it's >)
'''
''' And then, to record the memory usage of a step
''' - memorytest.NewStep("abc")
'''
''' To record and get the memory usage of every step:
''' - PrintMethod(memorytest.NewStep("abc").ToString)
'''
''' To record a step and get only results with an Increment of the Memory used > initial alertSize setting:
''' - If memoryTest.NewStepConditioned("abc") Then PrintMethod(memoryTest.LastStep)
'''
''' To get the sum of all Memory increments by step:
''' - PrintMethod(memorytest.GetMemoryUsedByStep("abc"))
''' </summary>
''' <remarks></remarks>
Friend Class MemoryLeakTest
Sub New(Optional ByVal newMemorySize As memorySize = memorySize.KBytes, Optional ByVal newAlertSize As Integer = 0)
_memorySize = newMemorySize
_alertSize = newAlertSize
End Sub
Private _memorySize As memorySize
Private _alertSize As Integer
Private _Priority As Integer
Private _Id As Integer
Private _Title As String
Private _MaxWorkingSet As IntPtr
Private _MinWorkingSet As IntPtr
Private _ProcessName As String
Private _StartInfo As System.Diagnostics.ProcessStartInfo
Private _PriorityClass As System.Diagnostics.ProcessPriorityClass
Private _MemorySteps As New List(Of MemoryStep)
Friend Function NewStep(ByVal _Step As String) As String
CallGC()
CheckMemoryStep(_Step)
'CallGC()
Return _MemorySteps(_MemorySteps.Count - 1).ToString
End Function
Friend Function NewStepConditioned(ByVal _Step As String) As Boolean
CallGC()
CheckMemoryStep(_Step)
'CallGC()
Return _MemorySteps(_MemorySteps.Count - 1).Alert
End Function
Friend Function LastStep() As String
Return _MemorySteps(_MemorySteps.Count - 1).ToString
End Function
Friend Function GetMemoryUsedByStep(ByVal NewStep As String) As String
Dim MemoryUsed As List(Of MemoryStep) = _MemorySteps.FindAll(Function(x) x._step = NewStep)
Return MemoryUsed.Sum(Function(x) x._inc_WorkingSet).ToString & " " & _memorySize.ToString
End Function
Friend Sub CallGC()
GC.Collect()
GC.WaitForPendingFinalizers()
'GC.Collect()
End Sub
Friend Sub CheckMemoryStep(ByVal newStep As String)
Using cp As Process = Process.GetCurrentProcess
If IsNothing(_StartInfo) Then
_Priority = cp.BasePriority
_Id = cp.Id
_Title = cp.MainWindowTitle
_MaxWorkingSet = cp.MaxWorkingSet
_MinWorkingSet = cp.MinWorkingSet
_PriorityClass = cp.PriorityClass
_ProcessName = cp.ProcessName
_StartInfo = cp.StartInfo
_MemorySteps.Add(New MemoryStep(newStep, cp, _memorySize, _alertSize))
Else
_MemorySteps.Add(New MemoryStep(newStep, cp, _memorySize, _alertSize, _MemorySteps(_MemorySteps.Count - 1)))
End If
End Using
End Sub
Friend Class MemoryStep
Sub New(ByVal newStep As String, ByVal cp As System.Diagnostics.Process, ByVal memSize As memorySize, ByVal alertSize As Integer, Optional ByVal oldStep As MemoryStep = Nothing)
_memorySize = memSize
_step = newStep
_NonPagedSystemMemory = CLng(cp.NonpagedSystemMemorySize64 / memSize)
_PagedMemory = CLng(cp.PagedMemorySize64 / memSize)
_PagedSystemMemory = CLng(cp.PagedSystemMemorySize64 / memSize)
_PeakPagedMemory = CLng(cp.PeakPagedMemorySize64 / memSize)
_PeakVirtualMemory = CLng(cp.PeakVirtualMemorySize64 / memSize)
_PeakWorkingSet = CLng(cp.PeakWorkingSet64 / memSize)
_PrivateMemory = CLng(cp.PrivateMemorySize64 / memSize)
_VirtualMemory = CLng(cp.VirtualMemorySize64 / memSize)
_WorkingSet = CLng(cp.WorkingSet64 / memSize)
If Not IsNothing(oldStep) Then
With oldStep
_inc_NonPagedSystemMemory = _NonPagedSystemMemory - ._NonPagedSystemMemory
_inc_PagedMemory = _PagedMemory - ._PagedMemory
_inc_PagedSystemMemory = _PagedSystemMemory - ._PagedSystemMemory
_inc_PeakPagedMemory = _PeakPagedMemory - ._PeakPagedMemory
_inc_PeakVirtualMemory = _PeakVirtualMemory - ._inc_PeakVirtualMemory
_inc_PeakWorkingSet = _PeakWorkingSet - ._PeakWorkingSet
_inc_PrivateMemory = _PrivateMemory - ._PrivateMemory
_inc_VirtualMemory = _VirtualMemory - ._VirtualMemory
_inc_WorkingSet = _WorkingSet - ._WorkingSet
End With
End If
If _inc_WorkingSet > alertSize Then
Alert = True
End If
End Sub
Private _NonPagedSystemMemory As Long
Private _PagedMemory As Long
Private _PagedSystemMemory As Long
Private _PeakPagedMemory As Long
Private _PeakVirtualMemory As Long
Private _PeakWorkingSet As Long
Private _PrivateMemory As Long
Private _VirtualMemory As Long
Private _WorkingSet As Long
Private _memorySize As memorySize
Private _inc_NonPagedSystemMemory As Long
Private _inc_PagedMemory As Long
Private _inc_PagedSystemMemory As Long
Private _inc_PeakPagedMemory As Long
Private _inc_PeakVirtualMemory As Long
Private _inc_PeakWorkingSet As Long
Private _inc_PrivateMemory As Long
Private _inc_VirtualMemory As Long
Friend _inc_WorkingSet As Long
Friend _step As String
Friend Alert As Boolean = False
Public Overrides Function ToString() As String
ToString = _step & vbTab & "memory usage: " & _WorkingSet.ToString & " " & _memorySize.ToString
If _inc_WorkingSet < 0 Then
ToString += " (- " & -_inc_WorkingSet.ToString & " " & _memorySize.ToString & ")"
Else
ToString += " (+ " & _inc_WorkingSet.ToString & " " & _memorySize.ToString & ")"
End If
Return ToString
End Function
End Class
Enum memorySize
MBytes = 1024000
KBytes = 1024
[Bytes] = 1
End Enum
End Class
这个类的使用应该是:
Class Test
Friend memorytest As New MemoryLeakTest(MemoryLeakTest.memorySize.MBytes)
Sub RunTest()
memorytest.NewStep("Start")
Method_1()
WriteToTextBox(memorytest.NewStep("Method_1").ToString)
Method_2()
WriteToTextBox(memorytest.NewStep("Method_2").ToString)
Method_3()
If memoryTest.NewStepConditioned("Method_3") Then WriteToTextBox(memoryTest.LastStep)
End Sub
Private Sub Method_1()
'Do something
End Sub
Private Sub Method_2()
'Do something
End Sub
Private Function Method_3()
'Do something
End Function
Private Sub WriteToTextBox(ByVal msg As String)
With TextBox1
.SelectionStart = .Text.Length
.SelectedText = VbCrlf & Date.Now.ToLongTimeString & Chr(9) & msg
End With
End Sub
End Class
在我看来效果很好,但是因为深入了解 GC 需要大量时间,而我目前没有,我会向社区询问这个类是否可以有效地用于查找内存泄漏,因为我构建了它.
【问题讨论】:
-
内存泄漏是指对象在不打算保持活动状态的情况下仍保持活动状态的情况。但是没有人可以检查意图。如果有办法自动检测到,所有垃圾收集器都已经包含它,以释放所有打算释放的对象。
-
@Holger 谢谢,我测试并且代码有效。我提供的链接也解释了这是一种有效的方法。有时,当您有数千行代码时,可能是一种快速查找泄漏的方法,您不觉得吗?如果代码有效,您是否对其进行了测试?
-
当我们只有“数千行代码”时,我们当然不需要内存分析工具。既然我们没有,我们肯定不会使用需要修改代码的工具。除此之外,不可能测试你的代码,因为你没有解释它应该做什么。显然,它应该记录内存使用情况并从中得出结论,这仅适用于非常简单的设置,而不是现实生活中的案例。
-
@Holger 感谢您的帮助。我不是专业的开发人员(可能你很快就认出了看代码),多年来,在学习的过程中,我在我的程序中添加了一些代码(在需要时也重写)......现在我的一些程序有大约 40.000 行代码。我从不关心内存泄漏,现在我意识到某个地方有很多泄漏。所以我正在努力解决所有问题。但老实说,我不喜欢购买、安装和研究分析器,所以我正在尝试手动了解泄漏(可能是事件)在哪里,我想用这段代码可能会很快......
-
您的方法的问题是,它要求您知道哪些对象正在泄漏(或至少有怀疑)以及这些对象应该可回收的时间(断言内存消耗类似于分配之前的点)。但是,如果您已经知道这些事情,则不需要该工具。但是现实生活中的应用程序通常不是那么简单,因为对象的生命周期重叠,所以没有一点内存消耗必须与另一个时间点相同。而且您仍然不知道哪个引用阻止了对象的收集。
标签: vb.net memory-leaks garbage-collection profiler