2010-04-30 85 views
0

我是一個在任何代碼中編寫「最佳實踐」等完整新手。 我傾向於只寫它,如果它工作,爲什麼修復它。Windows服務HTTPListener內存問題

那麼,這種工作方式是讓我登陸一些熱水。我正在編寫一個簡單的Windows服務來服務於單個網頁。 (這項服務將被合併到監視服務和一組服務器上的某些文件夾的另一個項目中。)

我的問題是,無論何時收到請求,內存使用情況都會每次請求跳過幾K,保持每一次請求。

現在我發現通過將GC.Collect放在混音中它會停在某個數字上,但是我確定它並不意味着以這種方式使用。我想知道如果我失去了一些東西或者沒有做一些我應該釋放內存的東西。

下面是代碼:

Public Class SimpleWebService : Inherits ServiceBase 
    'Set the values for the different event log types. 
    Public Const EVENT_ERROR As Integer = 1 
    Public Const EVENT_WARNING As Integer = 2 
    Public Const EVENT_INFORMATION As Integer = 4 
    Public listenerThread As Thread 
    Dim HTTPListner As HttpListener 
    Dim blnKeepAlive As Boolean = True 

    Shared Sub Main() 
     Dim ServicesToRun As ServiceBase() 
     ServicesToRun = New ServiceBase() {New SimpleWebService()} 
     ServiceBase.Run(ServicesToRun) 
    End Sub 

    Protected Overrides Sub OnStart(ByVal args As String()) 
     If Not HttpListener.IsSupported Then 
      CreateEventLogEntry("Windows XP SP2, Server 2003, or higher is required to " & "use the HttpListener class.") 
      Me.Stop() 
     End If 
     Try 
      listenerThread = New Thread(AddressOf ListenForConnections) 
      listenerThread.Start() 
     Catch ex As Exception 
      CreateEventLogEntry(ex.Message) 
     End Try 
    End Sub 

    Protected Overrides Sub OnStop() 
     blnKeepAlive = False 
    End Sub 

    Private Sub CreateEventLogEntry(ByRef strEventContent As String) 
     Dim sSource As String 
     Dim sLog As String 
     sSource = "Service1" 
     sLog = "Application" 
     If Not EventLog.SourceExists(sSource) Then 
      EventLog.CreateEventSource(sSource, sLog) 
     End If 
     Dim ELog As New EventLog(sLog, ".", sSource) 
     ELog.WriteEntry(strEventContent) 
    End Sub 

    Public Sub ListenForConnections() 
     HTTPListner = New HttpListener 
     HTTPListner.Prefixes.Add("http://*:1986/") 
     HTTPListner.Start() 
     Do While blnKeepAlive 
      Dim ctx As HttpListenerContext = HTTPListner.GetContext() 
      Dim HandlerThread As Thread = New Thread(AddressOf ProcessRequest) 
      HandlerThread.Start(ctx) 
      HandlerThread = Nothing 
     Loop 
     HTTPListner.Stop() 
    End Sub 

    Private Sub ProcessRequest(ByVal ctx As HttpListenerContext) 
     Dim sb As StringBuilder = New StringBuilder 
     sb.Append("<html><body><h1>Test My Service</h1>") 
     sb.Append("</body></html>") 
     Dim buffer() As Byte = Encoding.UTF8.GetBytes(sb.ToString) 
     ctx.Response.ContentLength64 = buffer.Length 
     ctx.Response.OutputStream.Write(buffer, 0, buffer.Length) 
     ctx.Response.OutputStream.Close() 
     ctx.Response.Close() 
     sb = Nothing 
     buffer = Nothing 
     ctx = Nothing 
     'This line seems to keep the mem leak down 
     'System.GC.Collect() 
    End Sub 
End Class 

請隨時critisise和撕裂的代碼,但請善待。我承認在編碼方面我不傾向於遵循最佳做法。

回答

2

你是對的,你應該不是正在做這個。刪除Collect()調用並讓它運行一週。任何像樣的.NET書籍都會討論垃圾收集器如何工作以及它如何工作而不是當您將對象設置爲Nothing時,會立即釋放內存。直到你消耗了2到8兆字節之間的內存,它纔會啓動。這不是泄漏,只是有效利用豐富的資源。

您爲每個單獨的連接使用一個新線程,這非常昂貴,並且當您獲得大量連接時很難縮放很差。考慮使用ThreadPool.QueueUserWorkItem代替。線程池線程非常便宜,它們的分配和執行由線程池管理器很好地控制。