C# C中的内部或嵌套作用域是否影响GC?

C# C中的内部或嵌套作用域是否影响GC?,c#,garbage-collection,scoping,C#,Garbage Collection,Scoping,以此为例,内部/嵌套作用域是否以任何方式影响GC或内存管理?从C++或C观点来看,在函数中声明或被初始化的任何在其他范围内未被引用或在定义范围之外声明的函数通常在函数超出范围后释放。GC在这种情况下也会做类似的事情吗?GC是否考虑这些内部范围?除了防止在范围外访问声明之外,我看不到此功能提供的任何其他功能。假设我们只是讨论引用类型: 内部/嵌套作用域是否以任何方式影响GC或内存管理 发布:不,他们没有。GC不关心局部变量的范围:它关心局部变量上次被引用的时间。让变量超出范围,或为其赋值null,

以此为例,内部/嵌套作用域是否以任何方式影响GC或内存管理?从C++或C观点来看,在函数中声明或被初始化的任何在其他范围内未被引用或在定义范围之外声明的函数通常在函数超出范围后释放。GC在这种情况下也会做类似的事情吗?GC是否考虑这些内部范围?除了防止在范围外访问声明之外,我看不到此功能提供的任何其他功能。

假设我们只是讨论引用类型:

内部/嵌套作用域是否以任何方式影响GC或内存管理

发布:不,他们没有。GC不关心局部变量的范围:它关心局部变量上次被引用的时间。让变量超出范围,或为其赋值null,都不会产生任何效果

这就是存在的原因

在调试中:局部变量将在方法的整个过程中保持活动状态,以帮助调试,而不管其作用域如何

除了防止在范围之外访问声明之外,我看不到该特性提供的任何其他功能


差不多就是这样。在C中很少看到只用于范围界定的内部作用域。

假设我们只讨论引用类型:

内部/嵌套作用域是否以任何方式影响GC或内存管理

发布:不,他们没有。GC不关心局部变量的范围:它关心局部变量上次被引用的时间。让变量超出范围,或为其赋值null,都不会产生任何效果

这就是存在的原因

在调试中:局部变量将在方法的整个过程中保持活动状态,以帮助调试,而不管其作用域如何

除了防止在范围之外访问声明之外,我看不到该特性提供的任何其他功能


差不多就是这样。很少看到内部范围仅限于C中的范围,C/P>P>C,C++与GC通常没有太大关系。 作用域通常位于完全不由GC管理的堆栈上。 此行为仅与lambda不同,如果引用lambda的外部作用域,则会为scopes变量创建一个对象,并且当lambda代码保留时,该对象可以由GC清理

垃圾收集器使用以下信息来确定 对象是否处于活动状态:

堆叠根。即时JIT提供的堆栈变量 编译器和堆栈遍历器。JIT优化可以延长或缩短时间 向服务器报告堆栈变量的代码区域 垃圾收集器

垃圾收集句柄。处理指向托管对象和 可以由用户代码或公共语言运行库分配

静态数据。应用程序域中的静态对象可能是 引用其他对象。每个应用程序域都跟踪其 静态对象

有关更多详细信息,请参阅:


<>和LAMBDAS:

C和C++中的GC通常没有太大关系。

作用域通常位于完全不由GC管理的堆栈上。 此行为仅与lambda不同,如果引用lambda的外部作用域,则会为scopes变量创建一个对象,并且当lambda代码保留时,该对象可以由GC清理

垃圾收集器使用以下信息来确定 对象是否处于活动状态:

堆叠根。即时JIT提供的堆栈变量 编译器和堆栈遍历器。JIT优化可以延长或缩短时间 向服务器报告堆栈变量的代码区域 垃圾收集器

垃圾收集句柄。处理指向托管对象和 可以由用户代码或公共语言运行库分配

静态数据。应用程序域中的静态对象可能是 引用其他对象。每个应用程序域都跟踪其 静态对象

有关更多详细信息,请参阅:


对于Lambdas:

IIRC,值类型仍然被清除

对于引用类型,它更复杂。引用超出范围,但GC负责最终清理实例。请看,运行GC的成本很高。当它收集并完成时,此应用程序中的每个其他线程都必须暂停

因此,GC在运行时是懒惰的。如果它只在应用程序关闭时运行一次,那么这就是理想的情况。除此之外,只有一种特殊的GC策略,即在生产代码中不应显式调用GC.Collect,否则OutOfMemory异常的危险将使其运行

当它运行时,每个实例的主要问题是我是否有一个对应用程序根的完整引用链 ? 它在多长时间前就超出了范围并不重要,除了发电系统之类的优化


请注意,有时您必须在非托管资源超出范围/立即执行清理工作。这就是终结器iDisposeable和使用块处理的内容。

IIRC,值类型仍然被清理

对于引用类型,它更复杂。引用超出范围,但GC负责最终清理实例。请看,运行GC的成本很高。当它收集并完成时,此应用程序中的每个其他线程都必须暂停

因此,GC在运行时是懒惰的。如果它只在应用程序关闭时运行一次,那么这就是理想的情况。除此之外,只有一种特殊的GC策略,即在生产代码中不应显式调用GC.Collect,否则OutOfMemory异常的危险将使其运行

当它运行时,每一个实例的关键是我是否有一个对应用程序根的完整引用链?它在多长时间前就超出了范围并不重要,除了发电系统之类的优化


请注意,有时您必须在非托管资源超出范围/立即执行清理工作。这就是终结器、iDisposeable和using blocks处理的内容。

GC绝对会管理堆栈上变量引用的对象,但GC只关心对象和引用。当然,堆栈上的变量可以包含引用,但范围与对象无关。基本上,对于GC,堆栈只是一个应用程序根是的,堆栈是一个对象根。但是这些是GC管理的对象的根。您可以有一个包含引用类型的范围,该范围位于堆栈上,这些引用是GC管理的对象的根。GC确实关心这些引用,因为我理解了他的问题,他问GC是否对作用域有反应。它不在C中,而不是在C++中。它仅在堆栈已在运行时将其视为根。即使没有对这些对象的引用,它们也可能已经在第二代中,不会在下一次GC运行中被收集。因此,当像他所要求的那样保留范围时,它们不一定被收集。GC绝对会管理堆栈上变量引用的对象,但GC只关心对象和引用。当然,堆栈上的变量可以包含引用,但范围与对象无关。基本上,对于GC,堆栈只是一个应用程序根是的,堆栈是一个对象根。但是这些是GC管理的对象的根。您可以有一个包含引用类型的范围,该范围位于堆栈上,这些引用是GC管理的对象的根。GC确实关心这些引用,因为我理解了他的问题,他问GC是否对作用域有反应。它不在C中,而不是在C++中。它仅在堆栈已在运行时将其视为根。即使没有对这些对象的引用,它们也可能已经在第二代中,不会在下一次GC运行中被收集。因此,如果像他所要求的那样保留范围,则不必收集它们。除此之外,只有一种特殊的GC策略,即在生产代码中不应显式调用GC.Collet,否则OutOfMemory异常的危险将使其运行。-事实并非如此。例如,如果分配预算为空,则会触发GCexceeded@canton7如果分配预算问题得不到解决,是否会导致OutOfMemory异常?如果是,那么我已经说过了。如果没有,它有什么作用?它必须用某种方式处理。不,不会。分配预算是每一代的,并且随着GC了解应用程序的分配模式而动态更新。它明显小于可用内存的总量:gen0从几kB/MB IIRC开始。《Pro.NET内存管理》一书有很多细节。GC将在应用程序启动期间频繁运行,通常在正常操作期间运行。具体参见AllocSmall ETWevent@canton7这些代是一个仅适用于GC的概念。如果没有问题,GC已经在运行了。而Pro.NET内存管理确实意味着它可能只适用于我提到的其中一种GC替代策略。恐怕我不确定你想说什么。不清楚您所说的特殊GC策略是什么意思-您是指正常的GC操作吗?我的观点是,GC进行收集是非常正常的,没有调用GC.Collect或系统内存不足,而且只有一种特殊的GC策略,即显式调用GC.Collet,您不应该在生产代码中使用它,否则OutOfMemory异常的危险会使它运行。-事实并非如此。例如,如果分配预算为空,则会触发GCexceeded@canton7如果无法解决分配预算问题,是否会导致OutOfMemory异常

D如果是,那么我已经说过了。如果没有,它有什么作用?它必须用某种方式处理。不,不会。分配预算是每一代的,并且随着GC了解应用程序的分配模式而动态更新。它明显小于可用内存的总量:gen0从几kB/MB IIRC开始。《Pro.NET内存管理》一书有很多细节。GC将在应用程序启动期间频繁运行,通常在正常操作期间运行。具体参见AllocSmall ETWevent@canton7这些代是一个仅适用于GC的概念。如果没有问题,GC已经在运行了。而Pro.NET内存管理确实意味着它可能只适用于我提到的其中一种GC替代策略。恐怕我不确定你想说什么。不清楚您所说的特殊GC策略是什么意思-您是指正常的GC操作吗?我的观点是,GC进行收集是非常正常的,没有调用GC.Collect或系统内存不足,通常是由程序员手动释放的。您所做的唯一类似的事情就是调用Dispose进行清理。其他所有操作都是自动完成的,但您对何时完成没有任何影响。@Holger很好地说,您只需调用构造函数而不使用新指令,就可以在堆栈上定义对象。一旦实例化函数超出范围或离开执行堆栈,它将丢弃构造对象使用的内存。如果在函数范围内用C++中的对象做了一个新的对象,那么您将有一个明确的内存泄漏,因为您公然需要将它释放,就像您刚刚把它放在堆上一样。这本身是昂贵的,所以一般来说,在函数中创建的任何不需要的东西都不应该在该函数的生命周期内放在堆上。但是GC和堆栈彼此无关。堆栈仅保存值或对实例的引用。如果没有新的值,则只能在堆栈上创建值类型。如果它们超出范围,则会被销毁,但这不是托管内存。没有什么不同的C++,一个int i在两种情况下都是分配堆栈内存,没有新的,并且你永远不必担心破坏。对象仅使用“new”创建,一旦所有引用超出范围,它们就会发出准备删除的信号,但您无法控制何时删除它们。C中的内存泄漏定义为,在GC发生后,您不再需要的某些对象不会从托管内存中移除/删除。因此,泄漏通常意味着某个变量持有对该对象的引用,您必须找出该引用仍然存储在何处、如何存储以及为什么存储。您被迫将类的实例放在堆上。没有办法。香草C++没有GC的概念。除非您自己使用或使用内存管理库。最接近你的是智能指针。你的意思是,通常由程序员手动释放。您所做的唯一类似的事情就是调用Dispose进行清理。其他所有操作都是自动完成的,但您对何时完成没有任何影响。@Holger很好地说,您只需调用构造函数而不使用新指令,就可以在堆栈上定义对象。一旦实例化函数超出范围或离开执行堆栈,它将丢弃构造对象使用的内存。如果在函数范围内用C++中的对象做了一个新的对象,那么您将有一个明确的内存泄漏,因为您公然需要将它释放,就像您刚刚把它放在堆上一样。这本身是昂贵的,所以一般来说,在函数中创建的任何不需要的东西都不应该在该函数的生命周期内放在堆上。但是GC和堆栈彼此无关。堆栈仅保存值或对实例的引用。如果没有新的值,则只能在堆栈上创建值类型。如果它们超出范围,则会被销毁,但这不是托管内存。没有什么不同的C++,一个int i在两种情况下都是分配堆栈内存,没有新的,并且你永远不必担心破坏。对象仅使用“new”创建,一旦所有引用超出范围,它们就会发出准备删除的信号,但您无法控制何时删除它们。C中的内存泄漏定义为,在GC发生后,您不再需要的某些对象不会从托管内存中移除/删除。因此,泄漏通常意味着某个变量持有对该对象的引用,您必须找出该引用仍然存储在何处、如何存储以及为什么存储。您被迫将类的实例放在堆上。没有办法。香草C++没有GC的概念。除非您自己使用或使用内存管理库。最接近的是智能指针。作用域在调试构建中也不起作用。最明显的方式是IL没有范围的概念。L
ifetime被扩展到了方法的末尾。@HansPassant所以它没有。我假设如果使用它们的变量在不同的作用域中,它将重用本地插槽,但似乎不是这样。固定的谢谢@HansPassant实际上,变量生存期是由JIT传递给GC的,在IL中没有表示,IIRC是的,您有本地插槽,但是这个生存期信息比这个更具体。在调试中,JIT告诉GC所有局部变量都在整个方法的作用域中,而不管是否有任何额外的作用域,这是肯定的吗?scope在调试构建中也不起作用。最明显的方式是IL没有范围的概念。生存期被延长到方法的末尾。@HansPassant因此不会。我假设如果使用它们的变量在不同的作用域中,它将重用本地插槽,但似乎不是这样。固定的谢谢@HansPassant实际上,变量生存期是由JIT传递给GC的,在IL中没有表示,IIRC是的,您有本地插槽,但是这个生存期信息比这个更具体。在调试中,JIT告诉GC所有的局部变量都在整个方法的作用域中,而不管是否有任何额外的作用域,这是真的吗