2010-04-30 15 views
0

Im un complet novice aux «meilleures pratiques» etc de l'écriture dans n'importe quel code. J'ai tendance à écrire juste un si ça marche, pourquoi le réparer.Windows Service HTTPListener Problème de mémoire

Eh bien, cette façon de travailler me fait tomber dans de l'eau chaude. J'écris un service simple de Windows pour server une seule page Web. (Ce service sera incorporé dans un autre projet qui surveille les services et certains dossiers sur un groupe de serveurs.)

Mon problème est que chaque fois qu'une requête est reçue, l'utilisation de la mémoire augmente de quelques K par requête et garde qoing à chaque demande. Maintenant, ive a trouvé qu'en plaçant GC.Collect dans le mix il s'arrête à un certain nombre mais je suis sûr qu'il n'est pas destiné à être utilisé de cette façon. Je me demandais si je manquais quelque chose ou si je ne faisais pas quelque chose que je devrais libérer de la mémoire.

Voici le code:

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 

S'il vous plaît ne hésitez pas à critisise et déchirer le code, mais à part s'il vous plaît BE NATURE QUE CE SOIT. J'ai admis que je n'ai pas tendance à suivre les meilleures pratiques en matière de codage.

Répondre

2

Vous avez raison, vous devriez pas en faisant cela. Supprimez l'appel Collect() et laissez-le s'exécuter pendant une semaine. Tout livre décent .NET parlera de la façon dont le garbage collector fonctionne et comment il le fait pas immédiatement libérer de la mémoire lorsque vous définissez un objet à Nothing. Il ne démarre pas tant que vous n'avez pas consommé entre 2 et 8 mégaoctets. Ce n'est pas une fuite, simplement l'utilisation efficace d'une ressource abondante.

Vous utilisez un nouveau thread pour chaque connexion individuelle, c'est assez cher et échelles très mal lorsque vous obtenez beaucoup de connexions. Envisagez d'utiliser ThreadPool.QueueUserWorkItem à la place. Les threads Threadpool sont très bon marché et leur allocation et leur exécution sont bien contrôlées par le gestionnaire de threads.