VS1*_*VS1 40 .net c# string performance string-interning
我想知道特定于.Net框架的字符串实习的过程和内部.还想知道使用实习的好处以及我们应该使用字符串实习来提高性能的场景/情况.虽然我已经从Jeffery Richter的CLR书中学习实习,但我仍然感到困惑,并希望更详细地了解它.
[编辑]使用示例代码询问具体问题如下:
private void MethodA()
{
string s = "String"; // line 1 - interned literal as explained in the answer
//s.intern(); // line 2 - what would happen in line 3 if we uncomment this line, will it make any difference?
}
private bool MethodB(string compareThis)
{
if (compareThis == "String") // line 3 - will this line use interning (with and without uncommenting line 2 above)?
{
return true;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
Ree*_*sey 30
通常,当您使用文字字符串值时,实习会自动发生.Interning提供的好处是,只要在文件内存中有一个副本,无论它使用多久.
话虽这么说,很少有理由在运行时生成你自己的字符串,或者甚至考虑正常开发的字符串实习.
如果您要通过比较可能相同的运行时生成的字符串进行大量工作(因为实习可以通过ReferenceEquals加速比较),可能会有一些好处.但是,这是一种高度专业化的用法,需要大量的分析和测试,并且除非存在已测量的问题,否则我不会考虑优化.
Ali*_*tad 20
实习是一个内部实现细节.与拳击不同,我认为在了解 Richter的书中所知道的内容并不是什么好处.
手动实施字符串的微优化优势是最小的,因此通常不推荐.
这可能描述了它:
class Program
{
const string SomeString = "Some String"; // gets interned
static void Main(string[] args)
{
var s1 = SomeString; // use interned string
var s2 = SomeString; // use interned string
var s = "String";
var s3 = "Some " + s; // no interning
Console.WriteLine(s1 == s2); // uses interning comparison
Console.WriteLine(s1 == s3); // do NOT use interning comparison
}
}
Run Code Online (Sandbox Code Playgroud)
har*_*rpo 20
这是一个"老"的问题,但我对它有不同的看法.
如果你将从一个小池中获得许多长寿命的字符串,实习可以提高内存效率.
在我的情况下,我在静态字典中实习另一种类型的对象,因为它们经常被重用,并且在将它们持久化到磁盘之前用作快速缓存.
这些对象中的大多数字段都是字符串,值池非常小(无论如何都比实例数小得多).
如果这些是瞬态对象,那么无关紧要,因为字符串字段会经常被垃圾收集.但由于对它们的引用被持有,它们的内存使用量开始累积(即使没有添加新的唯一值).
因此实际上,对象实际上减少了内存使用量,因此在实际执行时它们的字符串值实际上也是如此.
字符串的内部化会影响内存消耗.
例如,如果您读取字符串并将其保留在列表中以进行缓存; 并且完全相同的字符串出现10次,如果使用string.Intern,则字符串实际上只存储在内存中一次.如果不是,则将该字符串存储10次.
在下面的示例中,string.Intern变体消耗大约44 MB,而无版本(未注释)消耗1195 MB.
static void Main(string[] args)
{
var list = new List<string>();
for (int i = 0; i < 5 * 1000 * 1000; i++)
{
var s = ReadFromDb();
list.Add(string.Intern(s));
//list.Add(s);
}
Console.WriteLine(Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024 + " MB");
}
private static string ReadFromDb()
{
return "abcdefghijklmnopqrstuvyxz0123456789abcdefghijklmnopqrstuvyxz0123456789abcdefghijklmnopqrstuvyxz0123456789" + 1;
}
Run Code Online (Sandbox Code Playgroud)
内化还可以提高equals-compare的性能.实习生版本下面的示例大约需要1个时间单位,而非实习生需要7个时间单位.
static void Main(string[] args)
{
var a = string.Intern(ReadFromDb());
var b = string.Intern(ReadFromDb());
//var a = ReadFromDb();
//var b = ReadFromDb();
int equals = 0;
var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < 250 * 1000 * 1000; i++)
{
if (a == b) equals++;
}
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed + ", equals: " + equals);
}
Run Code Online (Sandbox Code Playgroud)
实习字符串具有以下特征:
这些特征的后果是:
您可以通过比较地址指针来测试两个内部字符串是否相等,这比比较字符串中的每个字符快得多.如果字符串很长并且以相同的字符开头,则尤其如此.您可以使用该Object.ReferenceEquals方法比较实习字符串,但使用string ==运算符更安全,因为它会检查字符串是否是互联网优先.
如果在应用程序中多次使用相同的字符串,则应用程序将仅在内存中存储一个字符串副本,从而减少运行应用程序所需的内存.
如果您实习许多不同的字符串,这将为那些永远不会释放的字符串分配内存,并且您的应用程序将消耗不断增加的内存量.
如果您有大量的实习字符串,则字符串实习可能变慢,并且线程将在访问实习字符串字典时相互阻塞.
只有在以下情况下才应使用字符串实习:
| 归档时间: |
|
| 查看次数: |
12515 次 |
| 最近记录: |