使用 out 参数时 CLR 的行为如何,方法 returns 后垃圾收集器的作用是什么?
How does the CLR behaves while using an out paramerter, what is the role of garbage collector as soon as the method returns?
为了更具体,请看下面的代码片段。
// Consider the itemCollection has list of items
// Consider the classItems is CollectionClass that is manipulated from somewhere
foreach(var item in itemCollection)
{
List<string> someNameCollection;
bool complete = false;
// itemCollection will be have thousand of items
// First parameter is single item and item.AnyItems means IEnumerable<AnyItem>
// classItems is CollectionClass that is manipulated from somewhere
if(DoSomething(item , item.Items, classItems, out someNameCollection , out complete )){
// if someNameCollection will be empty i will fill it in DoSomework() using the same foreach() logic that is used in DoSomething()
DoSomework(someNameCollection, complete);
}
}
private bool DoSomething(Item item, IEnumerable<AnyItem> anyItems, CollectionClass classItems, out List<string> nameCollection, out bool complete )
{
bool isNeeded = false;
complete = false;
nameCollection = new List<string>();
// loop for some parameter supplied, loop will run for 100k items
foreach(var item in anyItems)
{
// may be isNeeded true here
isNeeded = true;
//if true break the loop
// complete == true, may be here
}
if(!isNeeded)
{
foreach(var item in classItems)
{
// item are any name string
nameCollection.Add(item);
}
}
// another loop doing something
foreach()
{
// uses the nameCollection here depending upon
}
foreach(var item in nameCollection)
{
foreach()
{
// play with other things here
// do some manipulations
// may be, isNeeded = true here, if true break
}
}
// and isNeeded is either true or false will only be determined may be before the end of the method
return isNeeded;
}
现在的问题是,一旦 DoSomething() 方法 returns 它也填充了可用的 nameCollection 列表。我相信 nameCollection 不会在这里被自动垃圾收集,它会驻留在大对象堆中(会吗?),即使方法 returns 这个对象可能还没有从内存中释放(以前我有经历过这个)。现在再次在下一次调用 DoSomething() 时,nameCollection 将被填充并返回,它驻留在内存中并且不会被清除,尽管我们每次都创建一个新实例。
是否存在与我上面描述的相同的行为?如果不是,这里的行为是什么。如果那些集合对象驻留在内存中,我如何在不影响我的参数化列表的情况下刷新它?如果集合对象不驻留在内存中,out参数如何获取集合对象?
如果有人能在这里描述我的核心行为,我将不胜感激。我将非常乐意清除我的错误概念并添加正确的概念。
堆栈是您的 GC 之一 "roots"。在这种情况下,局部变量在调用代码的堆栈帧中正式声明(我们知道,因为 ldloca
只对正式声明的局部变量有意义——而不是堆栈上环境未声明的值),所以 GC 不会除了遍历堆栈框架检查局部变量(以及剩余堆栈 window,但这更复杂)之外,您无需做任何其他事情。归根结底,对于GC来说,这和方法里面的局部变量没什么区别:
SomeObject foo = new SomeObject();
附带说明:您的列表分配是多余且浪费的,可能只是:
List<string> nameCollection;
bool complete = false;
// DoSomething will be called thousand of times
if(DoSomething(out nameCollection, complete )){ // do the further task }
但是,如果是我,并且 DoSomething
被调用了数千次,我可能 会 在方法之外分配它,并将内容视为可丢弃的(在方法开始时调用 Clear()
),并在 中传递列表 - 以避免大量列表/数组分配。
为了更具体,请看下面的代码片段。
// Consider the itemCollection has list of items
// Consider the classItems is CollectionClass that is manipulated from somewhere
foreach(var item in itemCollection)
{
List<string> someNameCollection;
bool complete = false;
// itemCollection will be have thousand of items
// First parameter is single item and item.AnyItems means IEnumerable<AnyItem>
// classItems is CollectionClass that is manipulated from somewhere
if(DoSomething(item , item.Items, classItems, out someNameCollection , out complete )){
// if someNameCollection will be empty i will fill it in DoSomework() using the same foreach() logic that is used in DoSomething()
DoSomework(someNameCollection, complete);
}
}
private bool DoSomething(Item item, IEnumerable<AnyItem> anyItems, CollectionClass classItems, out List<string> nameCollection, out bool complete )
{
bool isNeeded = false;
complete = false;
nameCollection = new List<string>();
// loop for some parameter supplied, loop will run for 100k items
foreach(var item in anyItems)
{
// may be isNeeded true here
isNeeded = true;
//if true break the loop
// complete == true, may be here
}
if(!isNeeded)
{
foreach(var item in classItems)
{
// item are any name string
nameCollection.Add(item);
}
}
// another loop doing something
foreach()
{
// uses the nameCollection here depending upon
}
foreach(var item in nameCollection)
{
foreach()
{
// play with other things here
// do some manipulations
// may be, isNeeded = true here, if true break
}
}
// and isNeeded is either true or false will only be determined may be before the end of the method
return isNeeded;
}
现在的问题是,一旦 DoSomething() 方法 returns 它也填充了可用的 nameCollection 列表。我相信 nameCollection 不会在这里被自动垃圾收集,它会驻留在大对象堆中(会吗?),即使方法 returns 这个对象可能还没有从内存中释放(以前我有经历过这个)。现在再次在下一次调用 DoSomething() 时,nameCollection 将被填充并返回,它驻留在内存中并且不会被清除,尽管我们每次都创建一个新实例。
是否存在与我上面描述的相同的行为?如果不是,这里的行为是什么。如果那些集合对象驻留在内存中,我如何在不影响我的参数化列表的情况下刷新它?如果集合对象不驻留在内存中,out参数如何获取集合对象?
如果有人能在这里描述我的核心行为,我将不胜感激。我将非常乐意清除我的错误概念并添加正确的概念。
堆栈是您的 GC 之一 "roots"。在这种情况下,局部变量在调用代码的堆栈帧中正式声明(我们知道,因为 ldloca
只对正式声明的局部变量有意义——而不是堆栈上环境未声明的值),所以 GC 不会除了遍历堆栈框架检查局部变量(以及剩余堆栈 window,但这更复杂)之外,您无需做任何其他事情。归根结底,对于GC来说,这和方法里面的局部变量没什么区别:
SomeObject foo = new SomeObject();
附带说明:您的列表分配是多余且浪费的,可能只是:
List<string> nameCollection;
bool complete = false;
// DoSomething will be called thousand of times
if(DoSomething(out nameCollection, complete )){ // do the further task }
但是,如果是我,并且 DoSomething
被调用了数千次,我可能 会 在方法之外分配它,并将内容视为可丢弃的(在方法开始时调用 Clear()
),并在 中传递列表 - 以避免大量列表/数组分配。