【问题标题】:Checking Available Memory allocation in C#在 C# 中检查可用内存分配
【发布时间】:2011-01-30 04:29:41
【问题描述】:

我需要在我的应用程序中创建一个函数来设置其可用内存使用情况。我想要做的是当应用程序运行时,它达到设置的内存设置,我必须从保存到内存切换到保存到本地驱动器的文件以避免应用程序挂起。这是更好的方法吗?在内存分配方面这样做时要考虑哪些事项?希望你明白:)

谢谢,

吉普

【问题讨论】:

    标签: c# .net memory-management


    【解决方案1】:

    您可以使用System.Diagnostics.Process 或性能计数器获得粗略估计。但是,您可能应该重新考虑这种方法,因为您可能有更好的方法来判断您应该写入内存还是磁盘。

    首先,问题可能不是总内存使用量。这个问题听起来好像它存在于几个,甚至一个地方。我会考虑通过考虑您的需求来使这件事变得更智能。然后我会解决设计问题。

    也许您每次都需要保存到磁盘,但使用缓存代理来实现(以便从内存中读取)。也许您需要一个System.IO.Stream 的实现,它委托给具有预定义容量的MemoryStream,直到它接近该容量,然后切换到FileStream。也许它就像使用排队来计量系统特定部分的负载一样简单,这样内存就不会成为问题。

    在不了解您的具体问题的情况下,很难准确地告诉您应该做什么。我只能说,根据内存使用情况预测行为会导致一些难以测试的冒险行为,因此也难以维护。

    我想那是我的两分钱。


    编辑:

    添加请求的类。这不是 TDD 完成的,但可以让您了解解决此问题的一种方法。

    class UpgradingStream : Stream
    {
      // state pattern lives in the problem...
      private abstract class InternalState
      {
        private readonly Stream _underlyingStream;
    
        protected InternalState(Stream underlyingStream)
        {
          _underlyingStream = underlyingStream;
        }
    
        internal Stream GetUnderlyingStream()
        {
          return _underlyingStream;
        }
    
        // template method lives in the implementation of this state pattern
        internal InternalState Seek(long offset, SeekOrigin origin, out long result)
        {
          result = _underlyingStream.Seek(offset, origin);
    
          return GetNextState();
        }
    
        internal InternalState SetPosition(long value)
        {
          _underlyingStream.Position = value;
    
          return GetNextState();
        }
    
        internal InternalState SetLength(long value)
        {
          _underlyingStream.SetLength(value);
    
          return GetNextState();
        }
    
        internal InternalState Write(byte[] buffer, int offset, int count)
        {
          _underlyingStream.Write(buffer, offset, count);
    
          return GetNextState();
        }
    
        protected abstract InternalState GetNextState();
      }
    
      private class InMemoryOnly : InternalState
      {
        private readonly Func<Stream> _getUpgradedStream;
        private readonly int _threshold;
    
        private InMemoryOnly(int threshold, Func<Stream> getUpgradedStream)
          : base(new MemoryStream(threshold))
        {
          _threshold = threshold;
          _getUpgradedStream = getUpgradedStream;
        }
    
        internal static InternalState GetInstance(int threshold, Func<Stream> getUpgradedStream)
        {
          return new InMemoryOnly(threshold, getUpgradedStream);
        }
    
        protected override InternalState GetNextState()
        {
          if (GetUnderlyingStream().Length > _threshold)
          {
            var newStream = _getUpgradedStream();
    
            CopyStream(newStream);
    
            return Unrestricted.GetInstance(newStream);
          }
    
          return this;
        }
    
        private void CopyStream(Stream newStream)
        {
          var originalPosition = GetUnderlyingStream().Position;
    
          GetUnderlyingStream().Position = 0;
    
          int bytesRead;
    
          var buffer = new byte[65536];
    
          while ((bytesRead = GetUnderlyingStream().Read(buffer, 0, buffer.Length)) != 0)
          {
            newStream.Write(buffer, 0, bytesRead);
          }
    
          newStream.Position = originalPosition;
        }
      }
    
      private class Unrestricted : InternalState
      {
        private Unrestricted(Stream underlyingStream)
          : base(underlyingStream)
        {
        }
    
        internal static Unrestricted GetInstance(Stream stream)
        {
          return new Unrestricted(stream);
        }
    
        protected override InternalState GetNextState()
        {
          // state never changes once we are in a file or whatever
          return this;
        }
      }
    
      private InternalState _state;
    
      private UpgradingStream(int threshold, Func<Stream> getMoreEfficientStream)
      {
        _state = InMemoryOnly.GetInstance(threshold, getMoreEfficientStream);
      }
    
      internal static Stream GetInstance(int threshold, Func<Stream> getMoreEfficientStream)
      {
        return new UpgradingStream(threshold, getMoreEfficientStream);
      }
    
      public override bool CanRead
      {
        get { return _state.GetUnderlyingStream().CanRead; }
      }
    
      public override bool CanSeek
      {
        get { return _state.GetUnderlyingStream().CanSeek; }
      }
    
      public override bool CanWrite
      {
        get { return _state.GetUnderlyingStream().CanWrite; }
      }
    
      public override void Flush()
      {
        _state.GetUnderlyingStream().Flush();
      }
    
      public override long Length
      {
        get { return _state.GetUnderlyingStream().Length; }
      }
    
      public override long Position
      {
        get
        {
          return _state.GetUnderlyingStream().Position;
        }
        set
        {
          _state = _state.SetPosition(value);
        }
      }
    
      public override int Read(byte[] buffer, int offset, int count)
      {
        return _state.GetUnderlyingStream().Read(buffer, offset, count);
      }
    
      public override long Seek(long offset, SeekOrigin origin)
      {
        long result;
    
        _state = _state.Seek(offset, origin, out result);
    
        return result;
      }
    
      public override void SetLength(long value)
      {
        _state = _state.SetLength(value);
      }
    
      public override void Write(byte[] buffer, int offset, int count)
      {
        _state = _state.Write(buffer, offset, count);
      }
    
      public override void Close()
      {
        _state.GetUnderlyingStream().Close();
      }
    }
    

    【讨论】:

    • 你说得对:),你有你所说的示例代码吗?就内存和文件流而言,我是新手。我非常需要它。
    • 你的意思是让流从内存流切换到文件流?
    • 是的.. 但是是否可以将一个类放入内存流然后文件? :) 我的应用程序会在一段时间内填充该类。随着时间的推移,它的大小会增加,我认为这会导致我的应用程序中的进程变慢,有时会挂断。
    【解决方案2】:

    您不需要这样做:让操作系统自动处理它,它经过多年的性能调整和改进随着时间的推移而增加,通常会做很多工作。

    如需详细说明,请联系 Varnish 网络代理的制造商read this

    【讨论】:

    • 如果他创建了很多对象,就会触发垃圾回收。听起来他在试图避免触发 GC。
    【解决方案3】:

    您可能需要考虑为此应用程序使用memory mapped file

    如果您将数据写入内存映射文件,您可以在内存中访问大部分数据并根据需要自动分页。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-05
      • 2023-03-20
      • 2011-06-02
      • 2010-11-06
      • 2017-11-14
      • 1970-01-01
      • 2018-08-12
      相关资源
      最近更新 更多