2015-04-02 47 views
0

我需要对几个字符串进行简化。我正在使用StringBuilder作为如下String和StringBuilder消耗的内存是重复的

 StringBuilder result = new StringBuilder(length); 

长度是我想要在最后的字符串的“长度”。

“长度”是更高的数字。 要获得字符串我需要做的

 return result.ToString(); 

当我试图来分析我的应用我看到“StringBuilder的”和“字符串”正在采取的内存和重复相同的量所消耗的内存。 由于字符串的长度很长,占据了较大的内存百分比。

有没有更好的方法来解决这个内存问题?

+0

如果不知道你想解决的问题,很难回答这个问题。但是,如果您的应用程序由于大字符串而使用了太多的内存,那么看起来应该不会使用字符串。流式方法可能会更好。 – Dirk 2015-04-02 08:18:29

+0

是的,我们需要序列化它,并需要从另一侧读取。所以我们使用String。 – user3150546 2015-04-02 08:20:38

+1

那么,如果你想使用字符串,那么你必须忍受后果。但是,如果使用StringBuilder连接已知(在编译时)的字符串数量,那么使用+ -operator可能会更好,因为编译器会将其转换为String.Concat,并且可能会避免为临时对象。 – Dirk 2015-04-02 08:29:59

回答

1

要解决什么内存问题?你已经观察到的行为,但没有解释它是什么问题。

请注意,执行语句return result.ToString();后立即StringBuilder对象引用的对象有资格进行垃圾回收(假定这是对对象的唯一引用)。所以任何理论问题都应该是短暂的,可能会产生很少或根本没有实际影响的结果。换句话说:假设你建立了100个长度为N的字符串。这些字符串的名义开销是每个字符两个字节,所以内存中的开销是200 * N。在整个过程中,你正在构建这些字符串,额外的StringBuilder对象的名义内存中的成本为N.是的,它可能不止一个这些对象可能一次存在,但只有当它不重要时。否则,.NET会垃圾收集旧的,为新的空间腾出空间。

因此,您的最终结果是额外的开销为1%,比您的问题暗示的内存翻倍要少很多StringBuilder。这就是如果你只建立100个字符串。有效开销与您实际创建的字符串数量成反比,当然开销的重要性是直接与该相同数字成比例。换句话说,重要性越大,实际影响就越小。


更一般地说,你认为你会找到什么样的选择? StringBuilder类是处理可变字符串的最佳方法,即提供一种从部分创建字符串或以其他方式编辑字符串(例如从中删除棋子,重新排列字符串等)的方法。也就是说,您可以实现自己的字符串编辑类,以专门的方式完成类似的效果。

但是不管你用什么来编辑字符串,如果你完成的时候你想有一个System.String的实例,你必须在字符串中有两个数据副本:一个在可编辑版本,最后一个在System.String对象中。你不能编辑一个System.String对象(类型是不可变的),并且你不能神奇地将其他类型转换成System.String的实例。


(虽然顺便说一句,我会注意到,在旧的实现StringBuilder,从StringBuilder缓冲实际上只是复制的参考到新System.String对象。的无新副本除非在调用ToString()之后的某个时间点创建了字符串数据,否则StringBuilder对象再次被修改。StringBuilder的当前实现不会这样做,它针对涉及较长字符串的场景进行了优化,避免了“缓冲区大小的两倍”重新分配成本总是要求最终ToString()呼叫的数据副本的费用)。


现在,如果你能容忍使用字符串数据作为原始编辑对象(即StringBuilder或其他自定义类)和数据从来没有转换到System.String一个实例,那么这显然避免了二次办法数据副本。在这种方法中,你从不打扰ToString()的呼叫。永远。

但是,除此之外,你似乎要求不可能,因为没有机制可用于获取现有的字符缓冲区,并强制使用该缓冲区作为其内部表示。即它在将任何其他数据结构(包括StringBuilder)转换为System.String的实例的过程中是固有的,即该数据的第二个副本将被创建。

+0

谢谢你这么好的解释。我希望我需要将数据类型从字符串更改为字节或其他数据类型。因为字符串正被用于从一个系统到另一个系统的通信。 – user3150546 2015-04-07 09:01:28