C# 如何从内存中清除引用类型?
由于对象是引用类型,所以它们存储在堆中,而基本数据类型存储在堆栈上 但对象是基本数据类型和引用类型的集合,即对象可能有整数数据成员和/或其中可能有另一个对象 当作用域结束时,原始数据内存从堆栈中释放,但堆内存由垃圾收集器处理C# 如何从内存中清除引用类型?,c#,.net,memory,heap-memory,C#,.net,Memory,Heap Memory,由于对象是引用类型,所以它们存储在堆中,而基本数据类型存储在堆栈上 但对象是基本数据类型和引用类型的集合,即对象可能有整数数据成员和/或其中可能有另一个对象 当作用域结束时,原始数据内存从堆栈中释放,但堆内存由垃圾收集器处理 现在我的问题是:如果一个对象也有一个原始数据成员,那么它们什么时候被删除?很难解释这样一个基本的问题,但理解起来并不总是那么容易。然而,在过去的15年里,许多很好的解释被写了出来 如果你不想阅读它们(显然…),这里有一个非常简短(因此不完整)的总结:(注:我仍然强烈建议在文
现在我的问题是:如果一个对象也有一个原始数据成员,那么它们什么时候被删除?很难解释这样一个基本的问题,但理解起来并不总是那么容易。然而,在过去的15年里,许多很好的解释被写了出来 如果你不想阅读它们(显然…),这里有一个非常简短(因此不完整)的总结:(注:我仍然强烈建议在文献中调查) 注:以下部分根据有关“基本类型”术语的评论对话进行了少量编辑: (编辑) 在这个问题的上下文中,谈论“值类型”而不是“基元类型”更合适。无论类型是否为基元类型,在该上下文中唯一重要的是它是值类型还是引用类型。 (结束编辑) 现在重点是: 引用类型有一个引用(任何地方,如堆或堆栈中),它指向始终在堆上分配的实例。值类型存储在(堆或堆栈中的任何位置)立即嵌入该位置,因此没有间接寻址 样本:
- 值类型的局部变量:堆栈
- 引用类型的局部变量:实例本身在堆上,引用在堆栈上
- 成员变量(值类型):嵌入实例的分配空间中,该实例是其成员变量李>
- 成员变量(引用类型):其引用嵌入到实例的分配空间中,该实例是成员变量,其实例位于堆上
答:当包含对象被移除时。(基于4个示例,希望这一点很清楚:包含对象可以在堆上或堆栈上,因此“包含对象删除”可以是GC集合或从方法返回时设置的简单堆栈指针。)很难解释这样一个基本问题,但并不总是很容易理解。然而,在过去的15年里,许多很好的解释被写了出来 如果你不想阅读它们(显然…),这里有一个非常简短(因此不完整)的总结:(注:我仍然强烈建议在文献中调查) 注:以下部分根据有关“基本类型”术语的评论对话进行了少量编辑: (编辑) 在这个问题的上下文中,谈论“值类型”而不是“基元类型”更合适。无论类型是否为基元类型,在该上下文中唯一重要的是它是值类型还是引用类型。 (结束编辑) 现在重点是: 引用类型有一个引用(任何地方,如堆或堆栈中),它指向始终在堆上分配的实例。值类型存储在(堆或堆栈中的任何位置)立即嵌入该位置,因此没有间接寻址 样本:
- 值类型的局部变量:堆栈
- 引用类型的局部变量:实例本身在堆上,引用在堆栈上
- 成员变量(值类型):嵌入实例的分配空间中,该实例是其成员变量李>
- 成员变量(引用类型):其引用嵌入到实例的分配空间中,该实例是成员变量,其实例位于堆上
struct
类型)是局部变量时存储在堆栈上。如果已装箱,它们也可以存储在堆上,或者存储在数组中,或者,正如您所注意的,存储在引用类型的字段中
引用类型有一个或多个引用,这些引用也可能存储在堆栈上,本地引用通过堆栈寻址,对象本身在堆上的表示形式也可以存储在堆栈上
当作用域结束时,原始数据内存从堆栈中释放,但堆内存由垃圾收集器处理
不完全是
首先,没有真正的“释放”操作。假设我们使用堆栈上的4个插槽来存储值1-4*:
[1][2][3][4][ ][ ][ ][ ]
^
Using up to here.
(为了简单起见,我将完全忽略函数调用之间发生的事情)
现在我们停止使用最后两个插槽。没有必要“发布”任何内容:
[1][2][3][4][ ][ ][ ][ ]
^
Using up to here.
[1][2][5][4][ ][ ][ ][ ]
^
Using up to here.
仅当我们转到(例如,使用1个新插槽存储值5)时,我们需要覆盖任何内容:
[1][2][3][4][ ][ ][ ][ ]
^
Using up to here.
[1][2][5][4][ ][ ][ ][ ]
^
Using up to here.
“释放”只是改变了哪些内存被认为正在使用,哪些内存被认为可用
现在考虑下面的C代码:
假设您使用值42
调用它。堆栈的相关部分是:
[42]
^
Using up to here.
现在,在int result=num+1之后代码>范围中有两个值<代码>结果
和num
。因此,堆栈可能是:
[42][43]
^
Using up to here.
但是,num
不再使用。编译器和jitter知道这一点,因此他们可能重复使用了相同的插槽:
[43]
^
Using up to here.
因为“在scop中”
[Sync][RTTI][Field0][Field1] … [FieldN]