为什么字符串指针位置不同?
Why string pointer position is different?
为什么每次运行应用程序时字符串指针的位置都不同,当我使用 StringBuilder
但当我声明一个变量时相同?
void Main()
{
string str_01 = "my string";
string str_02 = GetString();
unsafe
{
fixed (char* pointerToStr_01 = str_01)
{
fixed (char* pointerToStr_02 = str_02)
{
Console.WriteLine((Int64)pointerToStr_01);
Console.WriteLine((Int64)pointerToStr_02);
}
}
}
}
private string GetString()
{
StringBuilder sb = new StringBuilder();
sb.Append("my string");
return sb.ToString();
}
输出:
40907812
178488268
下次:
40907812
179023248
下次:
40907812
178448964
str_01
持有对常量字符串的引用。然而,StringBuilder
动态构建字符串实例,因此 returned 字符串实例与具有相同内容的常量字符串在引用上不是同一实例。 System.Object.ReferenceEquals()
将 return false
.
由于 str_01
是对常量字符串的引用,它的数据可能存储在可执行文件的数据部分中,它始终在应用程序虚拟地址 space 中获得相同的地址。
编辑:
使用PE.Explorer或类似软件打开编译后的.exe文件,可以看到UTF-8编码的"my string"文本。它存在于文件的 .data 部分,包括首选虚拟地址,该部分应加载到进程虚拟内存中。
然而,我无法重现 str_01
在应用程序的多次运行中具有相同的地址,可能是因为我的 x64 Windows 8.1 执行 Address space layout randomization (ASLR)。因此,所有指针在应用程序的多次运行中都将不同,即使是那些直接指向加载的 PE 部分的指针也是如此。
仅仅因为两个字符串相等并不意味着它们指向相同的引用(我猜这意味着具有相同的指针),C# 不会自动实习所有字符串,因为性能方面的考虑等等。如果您希望两个字符串的指针相同,您可以使用 string.Intern
.
实习 str_02
我不同意
的输出
Console.WriteLine((Int64)pointerToStr_01);
对你来说总是一样的,因为我亲自测试过它,以使我的观点更清楚。
让我们看看两种情况:
- 在字符串 str_01 = "my string" 的情况下,当您打印此变量的指针值时,它不会与以前相同,因为每次创建一个新的 String 对象(即字符串是不可变的)并且 "my string" 被分配给它。然后在 Fixed 语句中打印指针的值,该值在您再次执行程序时超出范围,并且不会记住以前的值。
- 我认为,到目前为止,您可以自行解释 StringBuilder 的行为。
同时检查:
string str_01 = GetString();
private static string GetString()
{
var sb = new String(new char[] {'m','y',' ','s','t','r','i','n','g'});
return sb;
}
当我使用 fixed 时,它将分配内存
由于 str_01 是常量字符串,它会在执行时分配内存并每次都指向相同的位置
fixed (char* pointerToStr_01 = str_01)
但在
的情况下
fixed (char* pointerToStr_02 = str_02)
它动态分配内存,因此指向位置每次都不同
因此每次我们 运行
时字符串指针都不同
为什么每次运行应用程序时字符串指针的位置都不同,当我使用 StringBuilder
但当我声明一个变量时相同?
void Main()
{
string str_01 = "my string";
string str_02 = GetString();
unsafe
{
fixed (char* pointerToStr_01 = str_01)
{
fixed (char* pointerToStr_02 = str_02)
{
Console.WriteLine((Int64)pointerToStr_01);
Console.WriteLine((Int64)pointerToStr_02);
}
}
}
}
private string GetString()
{
StringBuilder sb = new StringBuilder();
sb.Append("my string");
return sb.ToString();
}
输出:
40907812
178488268
下次:
40907812
179023248
下次:
40907812
178448964
str_01
持有对常量字符串的引用。然而,StringBuilder
动态构建字符串实例,因此 returned 字符串实例与具有相同内容的常量字符串在引用上不是同一实例。 System.Object.ReferenceEquals()
将 return false
.
由于 str_01
是对常量字符串的引用,它的数据可能存储在可执行文件的数据部分中,它始终在应用程序虚拟地址 space 中获得相同的地址。
编辑:
使用PE.Explorer或类似软件打开编译后的.exe文件,可以看到UTF-8编码的"my string"文本。它存在于文件的 .data 部分,包括首选虚拟地址,该部分应加载到进程虚拟内存中。
然而,我无法重现 str_01
在应用程序的多次运行中具有相同的地址,可能是因为我的 x64 Windows 8.1 执行 Address space layout randomization (ASLR)。因此,所有指针在应用程序的多次运行中都将不同,即使是那些直接指向加载的 PE 部分的指针也是如此。
仅仅因为两个字符串相等并不意味着它们指向相同的引用(我猜这意味着具有相同的指针),C# 不会自动实习所有字符串,因为性能方面的考虑等等。如果您希望两个字符串的指针相同,您可以使用 string.Intern
.
str_02
我不同意
的输出 Console.WriteLine((Int64)pointerToStr_01);
对你来说总是一样的,因为我亲自测试过它,以使我的观点更清楚。
让我们看看两种情况:
- 在字符串 str_01 = "my string" 的情况下,当您打印此变量的指针值时,它不会与以前相同,因为每次创建一个新的 String 对象(即字符串是不可变的)并且 "my string" 被分配给它。然后在 Fixed 语句中打印指针的值,该值在您再次执行程序时超出范围,并且不会记住以前的值。
- 我认为,到目前为止,您可以自行解释 StringBuilder 的行为。
同时检查:
string str_01 = GetString();
private static string GetString()
{
var sb = new String(new char[] {'m','y',' ','s','t','r','i','n','g'});
return sb;
}
当我使用 fixed 时,它将分配内存
由于 str_01 是常量字符串,它会在执行时分配内存并每次都指向相同的位置
fixed (char* pointerToStr_01 = str_01)
但在
fixed (char* pointerToStr_02 = str_02)
它动态分配内存,因此指向位置每次都不同
因此每次我们 运行
时字符串指针都不同