2016-08-19 65 views
2

我正在創建一個網頁flooder來測試我的服務器上的一些安全性。 我有這樣的代碼:C#線程Ram使用

static void Main(string[] args) 
{ 
    string url; 
    int times; 
    Console.WriteLine("Inserisci l'indirizzo(pagina specifica) da floodare"); 
    url = Console.ReadLine(); 
    Console.WriteLine("Quante volte?"); 
    times = Int32.Parse(Console.ReadLine()); 
    System.Net.ServicePointManager.DefaultConnectionLimit = 350; 
    var block = new System.Threading.Tasks.Dataflow.ActionBlock<int>(async i => 
    { 
     try 
     { 
      await Work(i, url); 
     } 
     catch (Exception e) 
     { 

     } 
    }, new System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 350 }); 

    for(int i = 0; i < times; i++) 
    { 
     block.Post(i); 
    } 
    block.Complete(); 

    Task.WaitAll(block.Completion); 
} 
private static async Task<bool> Work(int i, string url) 
{ 
    if (i % 1000 == 0) 
     Console.WriteLine(i); 

    new WebClient().UploadValuesTaskAsync(url, new System.Collections.Specialized.NameValueCollection()); 

    //await Task.Delay(1); 
    return true; 
} 
} 

它的工作得很好,但它有一個問題。如果我設置的請求數量非常高(如20萬或更多),它會使用很多內存。在130萬個請求中,它使用3.3gb的內存。我試圖處理一切,以任何方式釋放RAM,但似乎塊變量存儲每個線程直到它完成。我該如何解決這個問題?

+0

爲什麼你不在'Work()'內部等待'UploadValuesTaskAsync'?你有沒有嘗試處理'WebClient'? – aghidini

+0

是的,我嘗試過。我不想等待它完成,我只是想運行它,我不關心結果 – LifeRewind

+0

@LifeRewind,你試過內存分析器嗎?哪些對象不是由GC收集的? –

回答

1

我發現了什麼。您正在使用WebClient,但不要處理它。 WebClient leaks

工作方法應該是這樣的:

private static async Task<bool> Work(int i, string url) 
{ 
    if (i % 1000 == 0) 
     Console.WriteLine(i); 

    // Must dispose to avoid leaks 
    using (var wc = new WebClient()) 
    { 
     await wc.UploadValuesTaskAsync(url, new System.Collections.Specialized.NameValueCollection()); 
    } 
    //await Task.Delay(1); 
    return true; 
} 

更新 我用HttpWebRequest和異步方法BeginGetResponse解決您的問題。完整的代碼是https://dotnetfiddle.net/ZecQku

namespace HttpWebRequest_HighIntesive 
{ 
    using System; 
    using System.Diagnostics; 
    using System.Net; 
    using System.Threading; 

    class ThreadParam 
    { 
     public int RequestsCount { get; private set; } 
     public CountdownEvent CountdownEvent { get; private set; } 
     public ThreadParam(int requestsCount, CountdownEvent countdownEvent) 
     { 
      RequestsCount = requestsCount; 
      CountdownEvent = countdownEvent; 
     } 
    } 
    class FinistRequestParam 
    { 
     public CountdownEvent CountdownEvent { get; private set; } 
     public HttpWebRequest HttpWebRequest { get; private set; } 
     public FinistRequestParam(CountdownEvent countdownEvent, HttpWebRequest httpWebRequest) 
     { 
      CountdownEvent = countdownEvent; 
      HttpWebRequest = httpWebRequest; 
     } 
    } 
    public class Program 
    { 
     static Uri _uri; 
     static volatile int _numberOfFinishedRequests; 
     static double _prevMemoryMb = 0; 

     public static int Main(string[] args) 
     { 
      int numOfRequests; 
      Console.Write("Enter URL(full format, for example, http://google.ru): "); 
      var url = Console.ReadLine(); 
      if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out _uri)){ 
       Console.WriteLine("Invalid URL. Exiting"); return -1; 
      } 
      Console.Write("Enter number of requests: "); 
      numOfRequests = Int32.Parse(Console.ReadLine()); 

      Console.WriteLine(""); 
      DoParallelRequests(numOfRequests); 

      Console.WriteLine("Finished. Press 'Enter' to quit"); 
      Console.ReadLine(); 
      return 0; 
     } 
     private static void DoParallelRequests(int numOfRequests) 
     { 
      // Play with DefaultConnectionLimit 
      // Increasing this value will increase speed, but also increase memory consumption 
      System.Net.ServicePointManager.DefaultConnectionLimit = 350; 
      Console.WriteLine("DefaultConnectionLimit: {0}", System.Net.ServicePointManager.DefaultConnectionLimit); 
      int threadCnt = Environment.ProcessorCount; 
      Console.WriteLine("Num of threads which creates HttpWebRequest: {0}", threadCnt); 
      // Initialize CountDownEvent with numOfRequests 
      CountdownEvent countDownOnTimes = new CountdownEvent(numOfRequests); 
      // Create timer for statistics 
      using (var timer = new Timer(TimerStatisticHanlder, Stopwatch.StartNew(), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5))) 
      { 
       // Create thread array 
       Thread[] threads = new Thread[threadCnt]; 
       // Initialize each thread and start it 
       for (int i = 0; i < threads.Length; i++) 
       { 
        threads[i] = new Thread(ThreadMethod); 
        // HACK Hope numOfRequests % threadCnt == 0 (evenly divisible) 
        // Start thread 
        threads[i].Start(new ThreadParam(numOfRequests/threadCnt, countDownOnTimes)); 
       } 
       // Will wait untill all request processed 
       countDownOnTimes.Wait(); 
      } 
     } 
     static void TimerStatisticHanlder(object obj) 
     { 
      Stopwatch sw = obj as Stopwatch; 
      // Calculate average speed 
      var aveageSpeed = Math.Round(_numberOfFinishedRequests/sw.Elapsed.TotalSeconds, 2); 
      // Get total memory 
      var totalMemoryMb = Math.Round((double)GC.GetTotalMemory(false)/1024/1024); 
      // Calculate memory delta 
      var memoryDeltaMb = totalMemoryMb - _prevMemoryMb; 
      // Print out statistics 
      Console.WriteLine("{0} Processed requests: {1}, Average speed: {2} requests per/s, Used memory: {3} Mbytes, Memory delta: {4}", DateTime.Now.ToString("HH:mm:ss"), _numberOfFinishedRequests, aveageSpeed, totalMemoryMb, memoryDeltaMb); 
      // Store total memory for delta calculation 
      _prevMemoryMb = totalMemoryMb; 
     } 
     private static void ThreadMethod(object state) 
     { 
      var threadParam = state as ThreadParam; 
      for (int i = 0; i <= threadParam.RequestsCount; i++) 
      { 
       // Create HttpWebRequest 
       HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_uri); 
       // Start it asynchronous 
       request.BeginGetResponse(new AsyncCallback(FinishRequest), new FinistRequestParam(threadParam.CountdownEvent, request)); 
      } 
     } 
     private static void FinishRequest(IAsyncResult result) 
     { 
      var reqParam = result.AsyncState as FinistRequestParam; 
      var request = reqParam.HttpWebRequest; 
      try 
      { 
       // Just end response 
       HttpWebResponse response = request.EndGetResponse(result) as HttpWebResponse; 
       // Release all resources 
       response.GetResponseStream().Dispose(); 
       response.Close(); 
       (request as IDisposable).Dispose(); 
      } 
      catch { } // Don't care about exceptions 

      // Mark yet another request finished 
      reqParam.CountdownEvent.Signal(); 
      // Increment total number of finished requests 
      Interlocked.Increment(ref _numberOfFinishedRequests); 
     } 
    } 
} 

測試應用程序的屏幕: Scree of test app

+0

這沒問題,但如果你等待,它會失去主要目標,進行洪水。但是,如果我把這個驚喜帶走,即​​使使用你的代碼。它使用了很多內存。我認爲問題在於我稱之爲功能的方式。我認爲塊變量存儲一切,直到它完成。你有什麼建議嗎? – LifeRewind

+0

謝謝你!我會試試看! – LifeRewind

1

Work你不等待IO完成。這使得Work完成得非常快。這有效地禁用了您想要的速率限制(MaxDegreeOfParallelism = 350)。

工作開始得比完成要快得多。這就是爲什麼工作項目會積累和消耗內存。

等待IO完成。