GC未收集IThreadPoolWorkItem

时间:2015-12-15 12:15:55

标签: c# mono garbage-collection clr profiler

我有一个嵌入式debian板,单声道运行.NET 4.0应用程序,具有固定数量的线程(没有操作,没有任务)。由于内存问题,我在Windows中使用CLR-Profiler来分析内存堆。 下面的图表现在显示,IThreadPoolWorkItems没有(至少不在第0代)收集:

Time line of heap memory

现在,我真的不知道这些物品可能在哪里使用以及它们为什么不被收集。

  • 这个行为的问题在哪里?IThreadPoolWorkItem在哪里使用?
  • 我该怎么做才能找到它们的使用位置(我无法通过搜索代码或查看CLR-Profiler来找到它们。)

修改

...
private Dictionary<byte, Telegram> _incoming = new Dictionary<byte, Telegram>();
private Queue<byte> _serialDataQueue;     
private byte[] _receiveBuffer = new byte[2048];
private Dictionary<Telegram, Telegram> _resultQueue = new Dictionary<Telegram, Telegram>();
private static Telegram _currentTelegram; 
ManualResetEvent _manualReset = new ManualResetEvent(false);
... 

// Called from other thread (class) to send new telegrams
public  bool Send(Dictionary<byte, Telegram> telegrams, out IDictionary<Telegram, Telegram> received)
{
  try
  {
      _manualReset.Reset();
      _incoming.Clear(); // clear all prev sending telegrams
      _resultQueue.Clear(); // clear the receive queue

      using (token = new CancellationTokenSource())
      {
          foreach (KeyValuePair<byte, Telegram> pair in telegrams)
          {
              _incoming.Add(pair.Key, pair.Value);
          }

          int result = WaitHandle.WaitAny(new[] { token.Token.WaitHandle, _manualReset });

          received = _resultQueue.Clone<Telegram, Telegram>();
          _resultQueue.Clear();
          return result == 1;
      }
  }
  catch (Exception err)
  {
      ... 
      return false;
  }
 }


// Communication-Thread
public void Run()
{
  while(true)
  {
     ...

     GetNextTelegram();   // _currentTelegram is set there and _incoming Queue is dequeued

     byte[] telegramArray = GenerateTelegram(_currentTelegram,  ... ); 

     bool telegramReceived = SendReceiveTelegram(3000, telegramArray);
     ... 
   }
}

// Helper method to send and receive telegrams
private bool SendReceiveTelegram(int timeOut, byte[] telegram)
{
        // send telegram
        try
        {
            // check if serial port is open
            if (_serialPort != null && !_serialPort.IsOpen)
            {
                _serialPort.Open();
            }

            Thread.Sleep(10);
            _serialPort.Write(telegram, 0, telegram.Length);
        }
        catch (Exception err)
        {
            log.ErrorFormat(err.Message, err);
            return false;
        }

        // receive telegram
        int offset = 0, bytesRead;

        _serialPort.ReadTimeout = timeOut; 

        int bytesExpected = GetExpectedBytes(_currentTelegram);

        if (bytesExpected == -1)
            return false;

        try
        {
            while (bytesExpected > 0 &&
              (bytesRead = _serialPort.Read(_receiveBuffer, offset, bytesExpected)) > 0)
            {
                offset += bytesRead;
                bytesExpected -= bytesRead;
            }

            for (int index = 0; index < offset; index++)
                _serialDataQueue.Enqueue(_receiveBuffer[index]);

            List<byte> resultList;

            // looks if telegram is valid and removes bytes from _serialDataQueue
            bool isValid = IsValid(_serialDataQueue, out resultList, currentTelegram);

            if (isValid && resultList != null)
            {
                // only add to queue if its really needed!!
                byte[] receiveArray = resultList.ToArray();

                _resultQueue.Add((Telegram)currentTelegram.Clone(), respTelegram);
            }

            if (!isValid)
            {
                Clear();
            }   

            return isValid;
        }
        catch (TimeOutException err) // Timeout exception 
        {
            log.ErrorFormat(err.Message, err);
            Clear();
            return false;
        }  catch (Exception err)
        {
            log.ErrorFormat(err.Message, err);
            Clear();
            return false;
        }
    }

谢谢你的帮助!

1 个答案:

答案 0 :(得分:0)

我发现,就像已经提到的消费者一样,&#34;问题&#34;是通过SerialPort进行通信。我找到了一个有趣的话题here

  

SerialPort有一个等待事件的后台线程(通过WaitCommEvent)。每当一个事件到来时,它就会对一个线程池工作进行排队   可能导致调用事件处理程序的项目。让我们关注一下   其中一个线程池线程。它试图锁定(快速   原因:存在将事件提升与结束同步;对于   更多细节见最后)一旦获得锁定,它会检查是否   可读的字节数高于阈值。如果是这样,   它会调用你的处理程序。

     

所以这个锁是你的处理程序不能单独调用的原因   线程池线程同时进行。

这肯定是他们不能立即收集的原因。我也尝试过不在我的SendReceiveTelegram方法中使用阻塞Read,但是使用SerialDataReceivedEventHandler导致了相同的结果。

所以对我来说,我会保留现状,除非你给我一个更好的解决方案,这些ThreadPoolWorkitems不再在队列中保留那么久。

感谢您的帮助以及您的负面评估:-D