Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 避免字符串内存泄漏_C#_String_Memory Leaks - Fatal编程技术网

C# 避免字符串内存泄漏

C# 避免字符串内存泄漏,c#,string,memory-leaks,C#,String,Memory Leaks,我在解析器中发现内存泄漏。我不知道如何解决那个问题。 让我们看看基本路线 private void parsePage() { String[] tmp = null; foreach (String row in rows) { tmp = row.Split(new []{" "}, StringSplitOptions.None); PrivateRow t = new PrivateRow();

我在解析器中发现内存泄漏。我不知道如何解决那个问题。 让我们看看基本路线

    private void parsePage() {
        String[] tmp = null;

        foreach (String row in rows) {
            tmp = row.Split(new []{" "}, StringSplitOptions.None);

            PrivateRow t = new PrivateRow();

            t.Field1 = tmp[1];
            t.Field2 = tmp[2];
            t.Field3 = tmp[3];
            t.Field4 = String.Join(" ", tmp);

            myBigCollection.Add(t);
        }
    }


    private void parseFromFile() {
        String[] tmp = null;

        foreach (String row in rows) {
            PrivateRow t = new PrivateRow();

            t.Field1 = "mystring1";
            t.Field2 = "mystring2222";
            t.Field3 = "mystring3333";
            t.Field4 = "mystring1 xxx yy zzz";

            myBigCollection.Add(t);
        }
    }
在集合(行是100000个元素的列表)上启动parsePage(),使我的应用程序从20MB增长到70MB

启动parseFromFile(),从文件中读取相同的集合,但避免拆分/联接,需要大约1MB的内存

使用MemoryProfiler,我看到了“t”字段和PrivateRow,kkep引用了String.Split()数组和Split.Join。 我想这是因为我分配了一个可以被垃圾收集的引用,而不是副本

好的,使用70mb并不是什么大不了的事,但当我开始生产时,有很多网站,它可以提高2.5-3GB


干杯

这本身不是内存泄漏。它实际上表现得很正常。第二个函数使用的内存要少得多,原因很简单,因为您只使用了四个字符串。这四个字符串中的每一个都只分配一次,随后对新t.Fieldx实例使用的字符串实际上引用了相同的字符串值。字符串是不可变的,因此如果多次引用相同的字符串值,则可以由相同的字符串实例处理。有关这方面的更多详细信息,请参阅上标记为“Interning”的段落


在第一个函数中,每个字段和循环中的每一次都有可能是不同的字符串。这只是更多样化的数据。只要您的PrivateRow对象存在,这些字符串就一直存在。如果您的应用程序内存使用非常关键,并且存在大量重复数据,则应使用枚举替换字符串值。

您根本没有内存泄漏,只是垃圾收集器需要时间来处理它

我想那是因为我分配了一个引用,而不是一个副本,可以 把垃圾收集起来

这不是正确的假设<分配期间复制代码>字符串,即使它是引用类型。这是一种特殊的,独特的类型

现在,如果您有密集的内存压力,那么可能的解决方案是什么呢。若要处理文件中的大量字符串,可以选择两个选项

1) 通过读取srteam(而不是一次加载所有文件),按顺序处理它们。在内存中加载尽可能少的数据/需要的数据/有意义

2) 再次使用,仅加载数据块并按顺序处理它们


第二个可以与第一个组合

正如其他人所说,这里没有内存泄漏的证据,只是延迟了垃圾收集。所有的内存最终都应该清理掉

话虽如此,您可以做几件事来帮助降低内存使用率或更快地恢复内存:

1) 你应该能够替换

t.Field4 = String.Join(" ", tmp);

您通过拆分
行创建了
tmp
,然后将其重新连接在一起。避免仅使用
创建新字符串


2) 调用
GC.Collect()请求立即垃圾回收。这不会减少方法中使用的内存,但会更快地释放内存。

您没有内存泄漏;你只是有一个使用一些内存的程序。别管它,让GC完成它的工作。您提到parsePage与parseFromFile在同一个集合上运行。但是它们都是从文件中加载的吗?解析页面解析一些HTML页面并将元素放入一个集合中,该集合必须在RAM中才能快速查看/编辑。程序关闭时,使用Protobuf将集合序列化到磁盘。当程序打开时,集合将被反序列化。我不知道为什么解析100000个元素需要70MB内存。保存磁盘上的数据大约需要5MB,而不是从磁盘RAM上获取30mb。元素是相同的。您不能用枚举替换任意字符串数据。因为问题是关于解析器的,所以我认为可以安全地假设字符串数据是关键的。还值得注意的是,OP看到的引用不是“对string.Split()数组”本身的引用,尽管它们可能是对该数组中元素的引用。此外,根据代码的运行方式,GC行为将有所不同:在调试版本中,GC的攻击性要比在发布版本中小得多。这一段是关于“保留”的。好吧,也许不是memoryleak,但我不知道为什么要从磁盘序列化/反序列化列表,至少分配一半的RAM。使用一个分析器,解析页面,它向我展示了很多连接/拆分引用。显然,在反序列化文件时,这些方法不存在,所以需要更少的RAM。调用GC无法解决问题(只有2-3MB)@Kaiser69,明白。这是一篇很有帮助的文章,但有一点需要记住,这个工具的存在是为了向您展示如何使用内存。事实表明,内存在使用并不是一件坏事。问题是正在使用的内存是否应该被使用。在您的情况下,只要您的PrivateRow对象处于“活动”状态,就可以使用内存。最后一次分配只是复制“错误”的一种方式,在生产阶段,Field4是最后3项拆分字符串的连接:)是的,我评估了您的解决方案,但我无法使用这些对象。我从和HttpStream中读取,将对象保存在RAM中(用于快速编辑/查看),然后在应用程序关闭时保存。
t.Field4 = row;