字符串如何在c#中起作用?

时间:2016-08-05 17:28:27

标签: c# string heap-memory stack-memory

我知道字符串是不可变的,一旦创建我们就无法改变它,我已经读过如果我们创建一个新的字符串对象并为它分配一个值然后我们在内部为同一个字符串对象分配另一个值实际上是另一个创建并赋值的对象。我们说我有:

string str = "dog";            
str =  "cat";  

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

我已经上传了一张图片,如果我对堆栈和堆的想法错了,我会道歉,这就是我提出这个问题的原因。 图片是否反映了第一行代码(string str = "dog";)中发生的情况?然后在第二行代码中会发生什么?堆中的dog值会发生变化吗?然后创建引用它的堆栈中的新对象?那么之前的物体会发生什么?他们有同名吗? 对于这么多问题,我很抱歉,但我认为正确理解这一点并了解幕后发生的事情非常重要...... enter image description here

4 个答案:

答案 0 :(得分:4)

当您将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”的内容,它会标记内存被删除并根据需要进行替换。

答案 1 :(得分:2)

你关闭了。您的图片准确地表示了第一行代码中发生的情况。但是,事情与您对第二行代码的描述略有不同。

对于行str = "cat";,在堆中创建第二个字符串对象,并更改str变量以引用该新对象。您离开了str指向"cat"和堆上的孤立"dog"对象而没有引用它。

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

答案 2 :(得分:2)

审核String Interning.Net String Intern tableCLR Intern Pool  基本上,公共语言运行时(CLR)维护一个[唯一]字符串值表,每当您在代码中操作字符串时,CLR会检查此实习表以查看您尝试创建的新值是否已存在或不。如果是,它只是重新分配您正在修改的变量以指向实习池中的该条目。如果没有,它会将值添加到池中并返回该新引用。池中的旧值(不再由变量引用)会收集垃圾。

答案 3 :(得分:1)

是的,有两个对象。不,他们没有相同的名字。尽量不要将变量视为"名称"对于对象本身本身 - 它更像是对象在内存中的位置的临时名称。 (将变量视为"名称"对于对象来说有点误导的原因是你可以有几个变量引用同一个对象;它不是这样的情况该对象有几个"名称"本身,或者有几个对象 - 这就是你正好存储引用的方式。)

" string str"最初有一个字符串" dog的引用。"分配" cat"到" str",变量现在有一个对字符串" cat的引用。"

两个字符串仍然存在于内存中(至少暂时存在),但是" dog"字符串不再可访问,因为您没有引用它(因此不再"知道"它的位置)。你事先并不知道它们在记忆中存在了多长时间,因为垃圾收集者可以删除“狗”#34;任何点都可以从内存中找到字符串,因为它不再有任何引用。

您可以通过对堆上对象的引用来纠正堆栈上的值 - 这是一个很好的区别。