当前位置: 首页 > 编程语言 > C#

C#参数参考与.net垃圾收集分享

时间:2023-04-10 12:52:41 C#

C#参数参考与.net垃圾收集关于参数的问题。如果我理解正确,方法中定义的变量存储在堆栈中,不受垃圾收集的影响。所以,在这个例子中:publicclassTest{publicTest(){}publicintDoIt(){intt=7;增量(reft);返回吨;}privateintIncrement(refintp){p++;}}DoIt()的返回值为8。由于t的位置在堆栈上,因此这块内存不能被垃圾回收或压缩,Increment()中的引用变量将始终指向t的正确内容。但是,假设我们有:publicclassTest{privateintt=7;publicTest(){}publicintDoIt(){增量(reft);返回吨;}privateintIncrement(refintp){p++;现在,t存储在堆上,因为它是我类的特定实例的值。如果我将这个值作为参考参数传递,也许这不是问题?如果我将t作为参考参数传递,p将指向t的当前位置。但是,如果垃圾收集器在压缩过程中移动了这个对象,它不会弄乱Increment()中对t的引用吗?或者垃圾收集器是否更新通过传递引用参数创建的引用?我根本不用担心这个?在MSDN(我能找到)上唯一提到的担心内存被压缩与将托管引用传递给非托管代码有关。希望这是因为我不必担心托管代码中的任何托管引用。?如果我理解正确,方法中定义的变量存储在堆栈中,不受垃圾收集的影响。这取决于你所说的“受影响”是什么意思。堆栈上的变量是垃圾收集器的根,因此它们肯定会影响垃圾收集。由于t的位置在堆栈上,因此该内存不能被垃圾收集或压缩,并且Increment()中的引用变量将始终指向t的正确内容。“不能”在这里用起来很奇怪。首先使用堆栈的关键是因为堆栈只用于永远不需要压缩的数据,而且它的生命周期总是已知的,所以永远不需要垃圾收集。这就是我们首先使用堆栈的原因。你似乎本末倒置。让我重复一遍以确保清楚:我们将这些东西存储在堆栈中的原因是因为它不需要被收集或压缩,因为它的生命周期是已知的。如果它的寿命未知,那么它就会堆积起来。例如,迭代器块中的局部变量因此位于堆上。现在,t存储在堆上,因为它是我的类的特定实例的值。正确的。如果我将这个值作为参考参数传递,也许这不是问题?不,没关系。如果我将t作为参考参数传递,p将指向t的当前位置。是的。尽管我更喜欢它的方式是p是变量t的别名。但是,如果垃圾收集器在压缩过程中移动了这个对象,它不会弄乱Increment()中对t的引用吗?不。垃圾收集器知道托管引用;这就是为什么它们被称为托管引用。如果GC移动了东西,托管引用仍然有效。如果您使用不安全代码将实际指针传递给t,那么您将需要将t的容器固定到位,以便垃圾收集器知道不要移动它。您可以使用C#中的fixed语句或通过为要修复的对象创建GCHandle来完成此操作。垃圾收集器是否更新通过传递引用参数创建的引用?是的。如果你不这样做,它会很脆弱。我根本不用担心这个?不,您将其视为非托管C++程序员-C++允许您完成这项工作,但C#不允许。请记住,托管内存模型的全部意义在于让您不必考虑这些事情。当然,如果你喜欢操心这些东西,你可以随时使用“不安全”的功能来关闭这些安全系统,然后你就可以尽情地写栈,写堆破错误了。不,你不必担心。基本上,调用方法(DoIt)有一个对Test实例的“实时”引用,这可以防止它被垃圾收集。我不确定它是否可以被压缩——但我怀疑它可以,GC能够发现哪些变量引用是被移动对象的一部分。换句话说——别担心。是否可以压缩应该不会造成问题。这正是你在最后一句话中提到的。压缩堆时,GC将移动所有需要的引用(对非托管内存的引用除外)。请注意,使用堆栈或堆与具有值或引用类型的实例变量相关。值类型(结构和“简单”类型,如int、double等)总是在堆栈上,类总是在堆上(堆栈上的是引用——指针——指向实例分配的内存)。编辑:正如下面评论中正确指出的那样,第二段写得太快了。如果一个值类型实例是一个类的成员,它不会存储在栈上,它会像任何其他成员一样在堆上。以上是C#学习教程:C#参数共享引用和.net垃圾回收。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场,如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处: