2014-04-15 2 views
0

비동기 멀티 스레드 TCP 서버를 간단하게 구현합니다. 메모리 사용이 계속 증가한다는 점을 제외하면 의도적으로 작동합니다. 조사한 결과 메모리가 정리되지 않은 모든 스레드 개체임을 알게되었습니다. 그러나 스레드는 로그 파일에 "호스트 연결이 끊어졌습니다"라고 쓰고 그 스레드가 실행되는 마지막 코드 줄이므로 자체 정리 작업을 수행 할 것으로 기대합니다. 그러나 그것은 일어나지 않는 것 같습니다. 모든 연결에 대해 스레드가 만들어지고 실행이 중지되지만 완전히 정리되지는 않습니다.스레드가 실행 완료 후 정리되지 않음

무슨 일입니까?

예외도 생성되지 않습니다.

private void AcceptNextClient() 
    { 
     if (acceptConnections) serverSocket.BeginAcceptTcpClient(new AsyncCallback(AcceptTcpClientCallback), serverSocket); 
    } 


    private void AcceptTcpClientCallback(IAsyncResult ar) 
    { 
     try 
     { 
      TcpListener serverSocket = (TcpListener)ar.AsyncState; 
      TcpClient clientConnection = serverSocket.EndAcceptTcpClient(ar); 
      new Thread(unused => HandleClientCommunication(clientConnection)).Start(); 
     } 
     catch (Exception ex) { Disk.AppendLog(ex.ToString()); } 
     AcceptNextClient(); 
    } 

    private void HandleClientCommunication(TcpClient tcpClient) 
    { 
     string hostName = ""; 
     try 
     { 
      using (StreamWriter sw = new StreamWriter(tcpClient.GetStream())) 
      using (StreamReader sr = new StreamReader(tcpClient.GetStream())) 
      { 
       hostName = Dns.GetHostEntry(((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address).HostName; 
       bool read = true; 
       while (read) 
       { 
        string buffer = sr.ReadLine(); 
        if (buffer == null) read = false; 
        else 
        { 
         if (buffer.ToUpper().Equals("CLOSE_CONNECTION")) read = false; 
         else 
         { 
          sw.WriteLine(buffer); 
          sw.Flush(); 
         } 
        } 
       } 
       tcpClient.Close(); 
      } 
     } 
     catch (Exception ex) 
     { 
      Disk.AppendLog(hostName + " " + ex.ToString()); 
     } 
     Disk.AppendLog("host disconnected"); 
    } 

    public static void AppendLog(string msg) 
    { 
     File.AppendAllText(exePath + "errors.log", DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + " " + msg + Environment.NewLine); 
    } 
+1

"스레드가 생성되어 실행을 멈추지 만 완전히 제거되지는 않습니다." 정확히 무엇을 결론 지을까요? 그리고 "기억이 증가했기 때문에"라고 말하십시오. 메모리 프로파일 러를 사용해 보셨습니까? –

+0

예 JetBrains .dotTrace를 시도하고 프로세스 탐색기에 .NET 성능에 대한 탭이 있습니다. .NET CLR LocksAndThreads 클라이언트가 연결할 때마다 스레드 개체 수를 명확하게 볼 수 있습니다. 그리고 연결을 끊을 때 다시 내려 가지 마십시오. 프로그램을 처음 시작하면 약 7MB이지만, 며칠 후에는 100MB 이상으로 늘어나고 계속 성장합니다. GC.Collect()를 수행해도 클리닝되지 않습니다. –

+0

"호스트 연결이 끊어졌습니다"라고 쓰여진 경우 스레드를 계속 유지하는 것으로 보이는 것은 아무것도 없습니다. 내 의심은 단순히 전체 수집을 수행 할만한 가치가 있다는 추억의 압력이 없다는 것입니다. 당신은'GC.Collect (GC.MaxGeneration, GCCollectionMode.Forced); GC.WaitForPendingFinalizers();'? 참고 : 프로덕션 코드에 그대로두면 안됩니다. 단순히 이것이 원인인지 여부를 식별하는 데 도움이됩니다. –

답변

0

가비지 수집기가 서비스로 실행되는 동안 실행할 수 없었던 것을 발견 한 후 답변을 찾았지만 양식으로 실행 중일 때 (그리고 모든 메모리 문제를 해결할 때) 실행했습니다. .

Main (string [] args)에서 [STAThread]를 제거하면 모든 문제가 해결되었습니다. 코드 자체에는 아무런 문제가 없었습니다.

http://support.microsoft.com/kb/828988

0

new Thread(unused => HandleClientCommunication(clientConnection)).Start(); 
     } 

같은 스레드를 사용하고 할 경우의 당신이 각 스레드로 더 이상 앱에 100 MB의 종료됩니다 초당 100 전화를 가정하면 여기에 내 생각이다 쓰레드가 실행을 끝내더라도 가비지 컬렉터가 항상 메모리가 수집된다는 것을 보장 할 수 없다는 것을 적어도 기억해야한다.
여기서 제안 할 수있는 것은 모든 코드를 Task를 사용하도록 전환하는 것입니다.
코드 (이것은 가능하면) 당신은 만들기 스레드를 통해

  • 을 작업을 사용해야하는 이유 다음은이

    Task.Factory.StartNew(unused => HandleClientCommunication(clientConnection)); 
         } 
    

    같은 것을보고 스레드를 파괴하는 것은 시간이

  • 의 측면 에서 비용이 많이 드는 작업입니다 것입니다
  • 많은 스레드가 있으면 메모리 리소스가 낭비되고 운영 체제에서 으로 인한 성능 저하 및 실행 가능한 스레드 간 컨텍스트 전환
  • 작업은 스레드 풀에서 예약됩니다. 특정 스레드 수는 사용 된 스케줄러에 따라 달라집니다. 응용 프로그램이 스레드 풀에 대해 많은 요청을하면 스레드 풀이이 스레드를 사용하여 개의 요청을 모두 처리하려고 시도합니다. 그러나 응용 프로그램이 스레드 풀 스레드가 처리 할 수있는 것보다 더 빨리 여러 개의 요청을 대기열에 넣는 경우 추가 스레드가 생성됩니다.
+0

시도해 보니 스레드 개체의 수가 더 적게 올라 갔지만 덜 올라간 것은 적었습니다. –

+0

생성 된 스레드가 많아서 제어 할 수 없으므로 정상입니다. Qeue –

+0

에 대한 Qeue 클래스를 사용하여 연결 수를 제한하려고 시도하는 것이 정상적이지 않습니다. 무서워요. 스레드의 수는 계속 올라가고 현재의 모든 연결이 닫혀 있더라도 높게 유지됩니다. –

관련 문제