我听过并读过一个字符串无法更改(不可变?).我想这应该是正确的.但我也听说过两个内容相同的字符串共享相同的内存空间(或者你称之为内存空间).它是否正确?
如果是这样,这是否意味着如果我创建一个包含数千个字符串的List,如果大多数字符串彼此相等,那么根本不会占用太多空间?
编辑:在下面的答案中,我将实习池称为AppDomain特定的; 我很确定这是我之前观察到的,但是String.Intern的MSDN文档表明整个过程都有一个实习池,这使得它更加重要.
原始答案
(我打算将此作为评论添加,但我认为这是一个非常重要的一点,需要额外的答案......)
正如其他人所解释的那样,字符串实习发生在所有字符串文字中,但不在"动态创建"字符串上(例如从数据库或文件中读取的字符串,或使用StringBuilder
或构建的字符串String.Format
).
但是,我不建议打电话String.Intern
来绕过后一点:它会在你的生命周期中AppDomain
填充实习池.相反,请使用仅限于您的使用的本地池.以下是此类池的示例:
public class StringPool { private readonly Dictionarycontents = new Dictionary (); public string Add(string item) { string ret; if (!contents.TryGetValue(item, out ret)) { contents[item] = item; ret = item; } return ret; } }
然后,您只需使用以下内容:
string data = pool.Add(ReadItemFromDatabase());
(请注意,池不是线程安全的;正常使用不需要它.)
通过这种方式,您可以在不再需要时立即丢弃池,而不是永远在内存中存在大量字符串.如果你真的想要,你也可以使它变得更聪明,实现LRU缓存或其他东西.
编辑:只是为了澄清为什么这比使用更好String.Intern
...假设你从数据库或日志文件中读取一堆字符串,处理它们,然后转移到另一个任务.如果你打电话String.Intern
给那些字符串,只要你还活着,它们就永远不会被垃圾收集AppDomain
- 甚至可能不会.如果加载多个不同的日志文件,则会逐渐在实习池中累积字符串,直到完成或内存不足为止.相反,我建议这样的模式:
void ProcessLogFile(string file) { StringPool pool = new StringPool(); // Process the log file using strings in the pool } // The pool can now be garbage collected
在这里,您可以获得同一文件中多个字符串的好处,这些字符串仅在内存中存在一次(或者至少只能过一次gen0),但是您不会污染"全局"资源(实习池).
这或多或少是真的.它被称为"字符串实习".字符串文字只在内存中出现一次,设置为相同值的每个变量都指向此单个表示.但是,代码中创建的字符串不会自动实现.
http://msmvps.com/blogs/manoj/archive/2004/01/09/1549.aspx