Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.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_Heap Memory_Stack Memory - Fatal编程技术网

字符串在c#中是如何工作的?

字符串在c#中是如何工作的?,c#,string,heap-memory,stack-memory,C#,String,Heap Memory,Stack Memory,我知道字符串是不可变的,一旦创建,我们就无法更改它。我读到,如果我们创建一个新的字符串对象,给它赋值,然后在内部给同一个字符串对象赋值,实际上会创建另一个对象,并给它赋值。假设我有: string str = "dog"; str = "cat"; 如果我写Console.WriteLine(str)返回cat。 那么内部有两个对象?但是他们有相同的名字吗?它是如何工作的?我对谷歌做了一些研究,但我还没有找到足够让我信服的东西,所以我可以澄清我的想法。 我知道字符

我知道字符串是不可变的,一旦创建,我们就无法更改它。我读到,如果我们创建一个新的字符串对象,给它赋值,然后在内部给同一个字符串对象赋值,实际上会创建另一个对象,并给它赋值。假设我有:

string str = "dog";            
str =  "cat";  
如果我写
Console.WriteLine(str)返回
cat
。 那么内部有两个对象?但是他们有相同的名字吗?它是如何工作的?我对谷歌做了一些研究,但我还没有找到足够让我信服的东西,所以我可以澄清我的想法。 我知道字符串是引用类型,所以堆栈中有一个对象引用堆中的一个值,在这种情况下会发生什么?(参见上面的代码)

我上传了一张图片,如果我对堆栈和堆的概念有错误,请向我道歉,这就是我问这个问题的原因。 图片是否反映了第一行代码(
string str=“dog”
)中发生的情况?那么在第二行代码中会发生什么呢??堆中的
dog
值是否更改?然后在堆栈中创建一个引用它的新对象?那么之前存在的物体会发生什么?他们有相同的名字吗?
我很抱歉问了这么多问题,但我认为正确理解这一点以及了解幕后发生了什么是非常重要的…

是的,有两个对象。不,他们的名字不一样。尽量不要把变量看作对象本身的“名称”——它更像是对象在内存中位置的临时名称。(将变量视为对象的“名称”有些误导的原因是,可以有多个变量引用同一个对象;对象本身并不是有多个“名称”,也不是有多个对象——这只是存储引用的方式)

字符串str最初引用字符串dog。将“cat”赋值给“str”后,变量现在引用字符串cat

这两个字符串仍然存在于内存中(至少暂时存在),但“dog”字符串不再可访问,因为您没有对它的引用(因此不再“知道”它的位置)。您不知道它们在内存中会存在多长时间,因为垃圾收集器可以随时从内存中删除“dog”字符串,因为不再有对它的任何引用


顺便说一句,堆栈上的值与堆上的对象的引用是正确的-这是一个很好的区别。

很接近。您的图片准确地表示第一行代码中发生的情况。然而,事情与您在第二行代码中描述的有点不同

对于行
str=“cat”,则在堆中创建第二个字符串对象,并将
str
变量更改为引用该新对象。剩下的
str
指向
“cat”
,堆上还有一个孤儿
“dog”
对象,没有对它的引用

垃圾收集器可能会清理
“dog”
对象,因为没有对它的引用。

查看或。

基本上,公共语言运行库(CLR)维护一个[唯一]字符串值的表,每当您在代码中操作字符串时,CLR都会检查这个intern表,以查看您尝试创建的新值是否已经在其中。如果是,它只是重新分配您正在修改的变量,以指向实习生池中的该条目。如果不是,则将该值添加到池中并返回该新引用。池中不再由变量引用的旧值将被垃圾回收

当您将
str
赋值给“dog”时,它会按照上面在内存中描述的那样执行:引用变量
str
现在“指向”刚刚实例化的字符串的位置

str => MEMORY LOCATION "1": "dog"
       MEMORY LOCATION "2":
       MEMORY LOCATION "3":
str
被重新分配给新字符串“cat”时,它也会在内存中创建,现在
str
被调整,使其指向新位置的“cat”

       MEMORY LOCATION "1": "dog"
str => MEMORY LOCATION "2": "cat"
       MEMORY LOCATION "3":

“狗”怎么了?现在它实际上是不可访问的,因为我们不再有对其位置的引用(在内存、堆中,术语在这种情况下是可互换的)。稍后,当垃圾收集器检查内存进行清理时,它会意识到没有引用“dog”的内容,它会根据需要标记内存以进行删除和替换。

我很难选择答案,因为您所有的答案都是非常描述性的,我现在已经澄清了这一点,谢谢!!!这个答案完全错了。字符串仅在编译时隐式插入。在运行时,只有当代码通过调用
string.Intern()
方法显式请求字符串时,字符串才会被插入。此外,一旦进入实习生池,
string
对象就永远不会被垃圾收集。他们无限期地留在那里。实习生池不是缓存,它主要是一个放置编译代码时发现的字符串文本的地方。