下载时内存优化

时间:2010-03-27 12:27:57

标签: c# optimization

你好,我有以下一段代码,我期待优化,因为我正在消耗大量的内存这个例程被大量使用

第一个优化是将stringbuilder构造移出下载例程并使其成为类的一个字段,然后我会在例程中清除它

你能否提出任何其他优化建议,或指出一些可以帮助我解决此问题的资源(网络文章,书籍等)。

我正在考虑用固定(更大)的缓冲区替换stringbuilder ......或者创建一个更大的字符串构建器

提前感谢。

   StreamWriter _writer;
   StreamReader _reader;

   public string Download(string msgId)
   {
       _writer.WriteLine("BODY <" + msgId + ">");
       string response = _reader.ReadLine();

       if (!response.StartsWith("222"))
           return null;

       bool done = false;
       StringBuilder body = new StringBuilder(256* 1024);
       do
       {
           response = _reader.ReadLine();

           if (OnProgress != null)
               OnProgress(response.Length);

           if (response == ".")
           {
               done = true;
           }
           else 
           {
               if (response.StartsWith(".."))
                   response = response.Remove(0, 1);

               body.Append(response);
               body.Append("\r\n");
           }
       } while (!done);

       return body.ToString();
   }

3 个答案:

答案 0 :(得分:1)

使用固定大小的缓冲区实际上会使问题变得更糟,因为您必须选择大于您可能填充的大小。每次都会重新创建此缓冲区 - 或者如果您在每次创建类时将其移动到方法之外。如果你将它保存为类属性,那么只要该类存在,它就会存在,而不仅仅是该方法执行的时间长度。

只要您需要将结果作为字符串返回,我就会坚持使用StringBuilder。我能想到的唯一其他选择是将其更改为使用过滤器流。也就是说,创建一个StreamReader,它包装您当前使用的阅读器,并以与Download方法相同的方式转换基础流。然后,消费类可以简单地使用您的StreamReader实现,您只需要处理每个块,而不是将整个内容保存在内存中。如果消费类无论如何需要整个事情,这对你不会有太多帮助,但我不知道你是如何使用它的。

答案 1 :(得分:0)

很难仅在此方法的上下文中提出建议,因为结果值是包含所接收数据的完整内容的单个字符串...但是这个方法迟早会收集数据,它需要是变成了一个字符数组。

可能值得问一下这个方法的调用者是否真的需要在内存中的整个响应;调用者可以一次处理一行数据,这样一次只需要一行内存吗? (如果是这样,使用IEnumerable<string>语句实现的yield可能会更好地工作而不会显着改变方法的实现)

关于内存分配,请记住,并非所有内存分配在.NET中都是相同的;超过大约85kb的分配得到不同的处理,当频繁分配/释放时会导致内存碎片化;见:http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

如果碎片是您的主要问题而您一次只处理一个文档,那么创建一个共享缓冲区并保持分配可以帮助您解决问题,但在假设之前检查这是否是您的问题。修理一些没有破坏的东西是浪费时间。

答案 2 :(得分:0)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace iGEENIESU_MemoryOptimization
{
    public partial class iGEENIEMemoryOptimize : Form
    {
        public iGEENIEMemoryOptimize()
        {
            InitializeComponent();
        }


        [StructLayout(LayoutKind.Sequential)]
        internal class MEMORYSTATUS
        {
            internal int length;
            internal int memoryLoad;
            internal uint totalPhys;
            internal uint availPhys;
            internal uint totalPageFile;
            internal uint availPageFile;
            internal uint totalVirtual;
            internal uint availVirtual;
        }

        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern bool GlobalMemoryStatus(MEMORYSTATUS buffer);

        internal bool bLoop;

        private void iGEENIEMemoryOptimize_Load(object sender, EventArgs e)
        {
            bLoop = true;
            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.WorkerSupportsCancellation = false;
            backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
            backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
            backgroundWorker2.DoWork += new DoWorkEventHandler(backgroundWorker2_DoWork);
            backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);

            backgroundWorker1.RunWorkerAsync();
            backgroundWorker2.RunWorkerAsync();

        }

        void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

           // MessageBox.Show("Ting Choo Chiaw has optimize your memory, have fun");
            Application.Exit();
        }

        void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.pbmemoryoptimiz.Value = e.ProgressPercentage;
        }

        void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
        {
            int iCount = 0;
            while (iCount<10)
            {

                iCount++;
                this.backgroundWorker1.ReportProgress(iCount, null);
                System.Threading.Thread.Sleep(1000);

            }
            bLoop = false;
        }

        void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            MEMORYSTATUS status = new MEMORYSTATUS();

            GlobalMemoryStatus(status);

            int mem = (int)status.totalPhys;

            byte[] src = null;
            bool bContinue = true;
            do
            {
                try
                {
                    src = new byte[mem];
                    int len = src.Length;

                    while (true && bLoop)
                    {
                        len--;
                        if (len <= 0)
                            return;

                        src[len] = 0;
                    }

                    bContinue = false;
                }
                catch (OutOfMemoryException)
                {
                    mem = (int)((double)mem * 0.99);
                }

            } while (bContinue);
            backgroundWorker1.ReportProgress(10);
            if (backgroundWorker2 != null)
                if (backgroundWorker2.IsBusy)
                    backgroundWorker2.CancelAsync();
            src = null; // free resources instancely

            GC.Collect();
            GC.GetTotalMemory(false);
            GC.Collect();
        }
    }
}