When an array is subject to Garbage Collection?
up vote
2
down vote
favorite
A few years ago I read the book the CLR via C# and the other day I got asked whether an array and still got a bit puzzled, the question was to figure out when the array in the method below is available to garbage collection:
public static double ThingRatio()
var input = new 1, 1, 2 ,3, 5 ,8 ;
var count = input.Length;
// Let's suppose that the line below is the last use of the array input
var thingCount = CountThings(input);
input = null;
return (double)thingCount / count;
According to the answer given here: When is an object subject to garbage collection? which states:
They will both become eligible for collection as soon as they are not
needed anymore. This means that under some circumstances, objects can
be collected even before the end of the scope in which they were
defined. On the other hand, the actual collection might also happen
much later.
I would tend to say that starting after line 6 (i.e. input = null;
) the array becomes subject to GC but I am not that sure... (I mean the array is supposedly surely no longer needed after the assignment, but also struggling that it's after the CountThings
call but at the same time the array is "needed" for the null assignment).
c# .net garbage-collection
|
show 8 more comments
up vote
2
down vote
favorite
A few years ago I read the book the CLR via C# and the other day I got asked whether an array and still got a bit puzzled, the question was to figure out when the array in the method below is available to garbage collection:
public static double ThingRatio()
var input = new 1, 1, 2 ,3, 5 ,8 ;
var count = input.Length;
// Let's suppose that the line below is the last use of the array input
var thingCount = CountThings(input);
input = null;
return (double)thingCount / count;
According to the answer given here: When is an object subject to garbage collection? which states:
They will both become eligible for collection as soon as they are not
needed anymore. This means that under some circumstances, objects can
be collected even before the end of the scope in which they were
defined. On the other hand, the actual collection might also happen
much later.
I would tend to say that starting after line 6 (i.e. input = null;
) the array becomes subject to GC but I am not that sure... (I mean the array is supposedly surely no longer needed after the assignment, but also struggling that it's after the CountThings
call but at the same time the array is "needed" for the null assignment).
c# .net garbage-collection
So... you're just having doubts about the accepted answer in that question you linked?
– Broots Waymb
Nov 8 at 16:09
@Broots Waymb I have a doubt between after the CountThings call and the null assignment
– Ehouarn Perret
Nov 8 at 16:10
1
After the CountThings call the value is still referenced - unless the compiler picks it up and refactors it somehow, I'd say that GC won't touch that value before null assignment.
– Szab
Nov 8 at 16:11
4
i would say its subject to GC before the line ofinput = null
if the compiler is smart enough. If you are wondering about whether you need to assign it to null to help GC then the answer is no. absolutely not necessary
– Steve
Nov 8 at 16:11
@Steve how can we find this out? I am thinking maybe checking the IL code maybe if the null is not "translated" then that means that this assignment is not needed to make it subject to garbage collection. I am not sure "how dumb" the compiler is.
– Ehouarn Perret
Nov 8 at 16:14
|
show 8 more comments
up vote
2
down vote
favorite
up vote
2
down vote
favorite
A few years ago I read the book the CLR via C# and the other day I got asked whether an array and still got a bit puzzled, the question was to figure out when the array in the method below is available to garbage collection:
public static double ThingRatio()
var input = new 1, 1, 2 ,3, 5 ,8 ;
var count = input.Length;
// Let's suppose that the line below is the last use of the array input
var thingCount = CountThings(input);
input = null;
return (double)thingCount / count;
According to the answer given here: When is an object subject to garbage collection? which states:
They will both become eligible for collection as soon as they are not
needed anymore. This means that under some circumstances, objects can
be collected even before the end of the scope in which they were
defined. On the other hand, the actual collection might also happen
much later.
I would tend to say that starting after line 6 (i.e. input = null;
) the array becomes subject to GC but I am not that sure... (I mean the array is supposedly surely no longer needed after the assignment, but also struggling that it's after the CountThings
call but at the same time the array is "needed" for the null assignment).
c# .net garbage-collection
A few years ago I read the book the CLR via C# and the other day I got asked whether an array and still got a bit puzzled, the question was to figure out when the array in the method below is available to garbage collection:
public static double ThingRatio()
var input = new 1, 1, 2 ,3, 5 ,8 ;
var count = input.Length;
// Let's suppose that the line below is the last use of the array input
var thingCount = CountThings(input);
input = null;
return (double)thingCount / count;
According to the answer given here: When is an object subject to garbage collection? which states:
They will both become eligible for collection as soon as they are not
needed anymore. This means that under some circumstances, objects can
be collected even before the end of the scope in which they were
defined. On the other hand, the actual collection might also happen
much later.
I would tend to say that starting after line 6 (i.e. input = null;
) the array becomes subject to GC but I am not that sure... (I mean the array is supposedly surely no longer needed after the assignment, but also struggling that it's after the CountThings
call but at the same time the array is "needed" for the null assignment).
c# .net garbage-collection
c# .net garbage-collection
edited Nov 8 at 16:12
asked Nov 8 at 16:06
Ehouarn Perret
82911130
82911130
So... you're just having doubts about the accepted answer in that question you linked?
– Broots Waymb
Nov 8 at 16:09
@Broots Waymb I have a doubt between after the CountThings call and the null assignment
– Ehouarn Perret
Nov 8 at 16:10
1
After the CountThings call the value is still referenced - unless the compiler picks it up and refactors it somehow, I'd say that GC won't touch that value before null assignment.
– Szab
Nov 8 at 16:11
4
i would say its subject to GC before the line ofinput = null
if the compiler is smart enough. If you are wondering about whether you need to assign it to null to help GC then the answer is no. absolutely not necessary
– Steve
Nov 8 at 16:11
@Steve how can we find this out? I am thinking maybe checking the IL code maybe if the null is not "translated" then that means that this assignment is not needed to make it subject to garbage collection. I am not sure "how dumb" the compiler is.
– Ehouarn Perret
Nov 8 at 16:14
|
show 8 more comments
So... you're just having doubts about the accepted answer in that question you linked?
– Broots Waymb
Nov 8 at 16:09
@Broots Waymb I have a doubt between after the CountThings call and the null assignment
– Ehouarn Perret
Nov 8 at 16:10
1
After the CountThings call the value is still referenced - unless the compiler picks it up and refactors it somehow, I'd say that GC won't touch that value before null assignment.
– Szab
Nov 8 at 16:11
4
i would say its subject to GC before the line ofinput = null
if the compiler is smart enough. If you are wondering about whether you need to assign it to null to help GC then the answer is no. absolutely not necessary
– Steve
Nov 8 at 16:11
@Steve how can we find this out? I am thinking maybe checking the IL code maybe if the null is not "translated" then that means that this assignment is not needed to make it subject to garbage collection. I am not sure "how dumb" the compiler is.
– Ehouarn Perret
Nov 8 at 16:14
So... you're just having doubts about the accepted answer in that question you linked?
– Broots Waymb
Nov 8 at 16:09
So... you're just having doubts about the accepted answer in that question you linked?
– Broots Waymb
Nov 8 at 16:09
@Broots Waymb I have a doubt between after the CountThings call and the null assignment
– Ehouarn Perret
Nov 8 at 16:10
@Broots Waymb I have a doubt between after the CountThings call and the null assignment
– Ehouarn Perret
Nov 8 at 16:10
1
1
After the CountThings call the value is still referenced - unless the compiler picks it up and refactors it somehow, I'd say that GC won't touch that value before null assignment.
– Szab
Nov 8 at 16:11
After the CountThings call the value is still referenced - unless the compiler picks it up and refactors it somehow, I'd say that GC won't touch that value before null assignment.
– Szab
Nov 8 at 16:11
4
4
i would say its subject to GC before the line of
input = null
if the compiler is smart enough. If you are wondering about whether you need to assign it to null to help GC then the answer is no. absolutely not necessary– Steve
Nov 8 at 16:11
i would say its subject to GC before the line of
input = null
if the compiler is smart enough. If you are wondering about whether you need to assign it to null to help GC then the answer is no. absolutely not necessary– Steve
Nov 8 at 16:11
@Steve how can we find this out? I am thinking maybe checking the IL code maybe if the null is not "translated" then that means that this assignment is not needed to make it subject to garbage collection. I am not sure "how dumb" the compiler is.
– Ehouarn Perret
Nov 8 at 16:14
@Steve how can we find this out? I am thinking maybe checking the IL code maybe if the null is not "translated" then that means that this assignment is not needed to make it subject to garbage collection. I am not sure "how dumb" the compiler is.
– Ehouarn Perret
Nov 8 at 16:14
|
show 8 more comments
3 Answers
3
active
oldest
votes
up vote
6
down vote
accepted
Remember objects and variables are not the same thing. A variable has a scope to particular method or type, but the object it refers to or used to refer to has no such concept; it's just a blob of memory. If the GC runs after input = null;
but before the end of the method, the array is just one more orphaned object. It's not reachable, and therefore eligible for collection.
And "reachable" (rather then "needed" ) is the key word here. The array object is no longer needed after this line: var thingCount = CountThings(input);
. However, it's still reachable, and so could not be collected at that point...
We also need to remember it isn't collected right away. It's only eligible to be collected. As a practical matter, I've found the .Net runtime doesn't tend to invoke the GC in the middle of a user method unless it really has to. Generally speaking, it is not needed or helpful to set a variable to null
early, and in some rare cases can even be harmful.
Finally, I'll add that the code we read and write is not the same code actually used by the machine. Remember, there is also a compile step to translate all this to IL, and later a JIT process to create the final machine code that really runs. Even concept of one line following next is already an abstraction away from what actually happens. One line may expand to be several lines of actual IL, or in some cases even be re-written to involve all new compiler-generated types as with closures or iterator blocks. So everything here is really only referring to the simple case.
true I think even at the IL stage (I played with sharplab.io) the null assignment already disappeared
– Ehouarn Perret
Nov 8 at 16:28
add a comment |
up vote
4
down vote
GC Myth: setting an object's reference to null will force the GC to collect it right away.
GC Truth: setting an object's reference to null will sometimes allow the GC to collect it sooner.
Taking part of the blogpost I'm referencing below and applying it to your question, the answer is as follows:
The JIT is usually smart enough to realize that input = null
can be optimized away. That leaves CountThings(input)
as the last reference to the object. So after that call, the input
is no longer used and is removed as a GC Root. That leaves the Object in memory orphaned (no references pointing to it), making it eligible for collection. When the GC actually goes about collecting it, is another matter.
More information to be found at To Null or Not to Null
add a comment |
up vote
1
down vote
No object can be garbage-collected while it is recognized as existing. An object will exist in .NET for as along as any reference to it exists or it has a registered finalizer, and will cease to exist once neither condition applies. References in objects will exist as long as the objects themselves exist, and references in automatic variables will exist as long as there is any means via which they will be observed. If the garbage collector detects that the only references to an object with no registered finalizer are held in weak references, those references will be destroyed, causing the object to cease to exist. If the garbage collector detects that the only references to an object with a registered finalizer are held in weak references, any weak references whose "track resurrection" property is false, a reference to the object will be placed in a strongly-rooted list of objects needing "immediate" finalization, and the finalizer will be unregistered (thus allowing it to cease to exist if and when the finalizer reaches a point in execution where no reference to the object could ever be observed).
Note that some sources confuse the triggering of an object's finalizer with garbage-collection, but an object whose finalizer is triggered is guaranteed to continue to exist for at least as long as that finalizer takes to execute, and may continue to exist indefinitely if any references to it exist when the finalizer finishes execution.
In your example, there are three scenarios that could apply, depending upon what CountThings
does with the passed-in reference:
If
CountThings
does not store a copy of the reference anywhere, or any copies of references that it does store get overwritten beforeinput
gets overwritten, then it will cease to exist as soon asinput
gets overwritten or ceases to exist [automatic-duration variables may cease to exist any time a compiler determines that their value will no longer be observed].If
CountThings
stores a copy of the reference somewhere that continues to exist after it returns, and the last extant reference is held by something other than a weak reference, then the object will cease to exist as soon as the last reference is destroyed.If the last existing reference the array ends up being held in a weak reference, the array will continue to exist until the first GC cycle where that is the case, whereupon the weak reference will be cleared, causing the array to cease to exist. Note that the lack of non-weak references to the array will only be relevant when a GC cycle occurs. It is possible (and not particularly uncommon) for a program to store a copy of a reference into a
WeakReference
,ConditionalWeakTable
, or other object holding some form of weak reference, destroy all other copies, and then read out the weak reference to produce a non-weak copy of the reference before the next GC cycle. If that occurs, the system will neither know nor care that there was a time when non non-weak copies of the reference existed. If the GC cycle occurs before the reference gets read out, however, then code which later examines the weak reference will find it blank.
A key observation is that while finalizers and weak references complicate things slightly, the only way in which the GC destroys objects is by invalidating weak forms of references. As far as the GC is concerned, the only kinds of storage that exist when the system isn't actually performing a GC cycle are those used by objects that exist, those used for .NET's internal purposes, and regions of storage that are available to satisfy future allocations. If an object is created, the storage it occupied will cease to be a region of storage available for future allocations. If the object later ceases to exist, the storage that had contained the object will also cease to exist in any form the GC knows about until the next GC cycle. The next GC cycle won't destroy the object (which had already ceased to exist), but will instead add the storage which had contained it back to its list of areas that are available to add future allocations (causing that storage to exist again).
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
accepted
Remember objects and variables are not the same thing. A variable has a scope to particular method or type, but the object it refers to or used to refer to has no such concept; it's just a blob of memory. If the GC runs after input = null;
but before the end of the method, the array is just one more orphaned object. It's not reachable, and therefore eligible for collection.
And "reachable" (rather then "needed" ) is the key word here. The array object is no longer needed after this line: var thingCount = CountThings(input);
. However, it's still reachable, and so could not be collected at that point...
We also need to remember it isn't collected right away. It's only eligible to be collected. As a practical matter, I've found the .Net runtime doesn't tend to invoke the GC in the middle of a user method unless it really has to. Generally speaking, it is not needed or helpful to set a variable to null
early, and in some rare cases can even be harmful.
Finally, I'll add that the code we read and write is not the same code actually used by the machine. Remember, there is also a compile step to translate all this to IL, and later a JIT process to create the final machine code that really runs. Even concept of one line following next is already an abstraction away from what actually happens. One line may expand to be several lines of actual IL, or in some cases even be re-written to involve all new compiler-generated types as with closures or iterator blocks. So everything here is really only referring to the simple case.
true I think even at the IL stage (I played with sharplab.io) the null assignment already disappeared
– Ehouarn Perret
Nov 8 at 16:28
add a comment |
up vote
6
down vote
accepted
Remember objects and variables are not the same thing. A variable has a scope to particular method or type, but the object it refers to or used to refer to has no such concept; it's just a blob of memory. If the GC runs after input = null;
but before the end of the method, the array is just one more orphaned object. It's not reachable, and therefore eligible for collection.
And "reachable" (rather then "needed" ) is the key word here. The array object is no longer needed after this line: var thingCount = CountThings(input);
. However, it's still reachable, and so could not be collected at that point...
We also need to remember it isn't collected right away. It's only eligible to be collected. As a practical matter, I've found the .Net runtime doesn't tend to invoke the GC in the middle of a user method unless it really has to. Generally speaking, it is not needed or helpful to set a variable to null
early, and in some rare cases can even be harmful.
Finally, I'll add that the code we read and write is not the same code actually used by the machine. Remember, there is also a compile step to translate all this to IL, and later a JIT process to create the final machine code that really runs. Even concept of one line following next is already an abstraction away from what actually happens. One line may expand to be several lines of actual IL, or in some cases even be re-written to involve all new compiler-generated types as with closures or iterator blocks. So everything here is really only referring to the simple case.
true I think even at the IL stage (I played with sharplab.io) the null assignment already disappeared
– Ehouarn Perret
Nov 8 at 16:28
add a comment |
up vote
6
down vote
accepted
up vote
6
down vote
accepted
Remember objects and variables are not the same thing. A variable has a scope to particular method or type, but the object it refers to or used to refer to has no such concept; it's just a blob of memory. If the GC runs after input = null;
but before the end of the method, the array is just one more orphaned object. It's not reachable, and therefore eligible for collection.
And "reachable" (rather then "needed" ) is the key word here. The array object is no longer needed after this line: var thingCount = CountThings(input);
. However, it's still reachable, and so could not be collected at that point...
We also need to remember it isn't collected right away. It's only eligible to be collected. As a practical matter, I've found the .Net runtime doesn't tend to invoke the GC in the middle of a user method unless it really has to. Generally speaking, it is not needed or helpful to set a variable to null
early, and in some rare cases can even be harmful.
Finally, I'll add that the code we read and write is not the same code actually used by the machine. Remember, there is also a compile step to translate all this to IL, and later a JIT process to create the final machine code that really runs. Even concept of one line following next is already an abstraction away from what actually happens. One line may expand to be several lines of actual IL, or in some cases even be re-written to involve all new compiler-generated types as with closures or iterator blocks. So everything here is really only referring to the simple case.
Remember objects and variables are not the same thing. A variable has a scope to particular method or type, but the object it refers to or used to refer to has no such concept; it's just a blob of memory. If the GC runs after input = null;
but before the end of the method, the array is just one more orphaned object. It's not reachable, and therefore eligible for collection.
And "reachable" (rather then "needed" ) is the key word here. The array object is no longer needed after this line: var thingCount = CountThings(input);
. However, it's still reachable, and so could not be collected at that point...
We also need to remember it isn't collected right away. It's only eligible to be collected. As a practical matter, I've found the .Net runtime doesn't tend to invoke the GC in the middle of a user method unless it really has to. Generally speaking, it is not needed or helpful to set a variable to null
early, and in some rare cases can even be harmful.
Finally, I'll add that the code we read and write is not the same code actually used by the machine. Remember, there is also a compile step to translate all this to IL, and later a JIT process to create the final machine code that really runs. Even concept of one line following next is already an abstraction away from what actually happens. One line may expand to be several lines of actual IL, or in some cases even be re-written to involve all new compiler-generated types as with closures or iterator blocks. So everything here is really only referring to the simple case.
edited Nov 8 at 20:09
answered Nov 8 at 16:17
Joel Coehoorn
303k94489717
303k94489717
true I think even at the IL stage (I played with sharplab.io) the null assignment already disappeared
– Ehouarn Perret
Nov 8 at 16:28
add a comment |
true I think even at the IL stage (I played with sharplab.io) the null assignment already disappeared
– Ehouarn Perret
Nov 8 at 16:28
true I think even at the IL stage (I played with sharplab.io) the null assignment already disappeared
– Ehouarn Perret
Nov 8 at 16:28
true I think even at the IL stage (I played with sharplab.io) the null assignment already disappeared
– Ehouarn Perret
Nov 8 at 16:28
add a comment |
up vote
4
down vote
GC Myth: setting an object's reference to null will force the GC to collect it right away.
GC Truth: setting an object's reference to null will sometimes allow the GC to collect it sooner.
Taking part of the blogpost I'm referencing below and applying it to your question, the answer is as follows:
The JIT is usually smart enough to realize that input = null
can be optimized away. That leaves CountThings(input)
as the last reference to the object. So after that call, the input
is no longer used and is removed as a GC Root. That leaves the Object in memory orphaned (no references pointing to it), making it eligible for collection. When the GC actually goes about collecting it, is another matter.
More information to be found at To Null or Not to Null
add a comment |
up vote
4
down vote
GC Myth: setting an object's reference to null will force the GC to collect it right away.
GC Truth: setting an object's reference to null will sometimes allow the GC to collect it sooner.
Taking part of the blogpost I'm referencing below and applying it to your question, the answer is as follows:
The JIT is usually smart enough to realize that input = null
can be optimized away. That leaves CountThings(input)
as the last reference to the object. So after that call, the input
is no longer used and is removed as a GC Root. That leaves the Object in memory orphaned (no references pointing to it), making it eligible for collection. When the GC actually goes about collecting it, is another matter.
More information to be found at To Null or Not to Null
add a comment |
up vote
4
down vote
up vote
4
down vote
GC Myth: setting an object's reference to null will force the GC to collect it right away.
GC Truth: setting an object's reference to null will sometimes allow the GC to collect it sooner.
Taking part of the blogpost I'm referencing below and applying it to your question, the answer is as follows:
The JIT is usually smart enough to realize that input = null
can be optimized away. That leaves CountThings(input)
as the last reference to the object. So after that call, the input
is no longer used and is removed as a GC Root. That leaves the Object in memory orphaned (no references pointing to it), making it eligible for collection. When the GC actually goes about collecting it, is another matter.
More information to be found at To Null or Not to Null
GC Myth: setting an object's reference to null will force the GC to collect it right away.
GC Truth: setting an object's reference to null will sometimes allow the GC to collect it sooner.
Taking part of the blogpost I'm referencing below and applying it to your question, the answer is as follows:
The JIT is usually smart enough to realize that input = null
can be optimized away. That leaves CountThings(input)
as the last reference to the object. So after that call, the input
is no longer used and is removed as a GC Root. That leaves the Object in memory orphaned (no references pointing to it), making it eligible for collection. When the GC actually goes about collecting it, is another matter.
More information to be found at To Null or Not to Null
answered Nov 8 at 16:18
rickvdbosch
2,81121119
2,81121119
add a comment |
add a comment |
up vote
1
down vote
No object can be garbage-collected while it is recognized as existing. An object will exist in .NET for as along as any reference to it exists or it has a registered finalizer, and will cease to exist once neither condition applies. References in objects will exist as long as the objects themselves exist, and references in automatic variables will exist as long as there is any means via which they will be observed. If the garbage collector detects that the only references to an object with no registered finalizer are held in weak references, those references will be destroyed, causing the object to cease to exist. If the garbage collector detects that the only references to an object with a registered finalizer are held in weak references, any weak references whose "track resurrection" property is false, a reference to the object will be placed in a strongly-rooted list of objects needing "immediate" finalization, and the finalizer will be unregistered (thus allowing it to cease to exist if and when the finalizer reaches a point in execution where no reference to the object could ever be observed).
Note that some sources confuse the triggering of an object's finalizer with garbage-collection, but an object whose finalizer is triggered is guaranteed to continue to exist for at least as long as that finalizer takes to execute, and may continue to exist indefinitely if any references to it exist when the finalizer finishes execution.
In your example, there are three scenarios that could apply, depending upon what CountThings
does with the passed-in reference:
If
CountThings
does not store a copy of the reference anywhere, or any copies of references that it does store get overwritten beforeinput
gets overwritten, then it will cease to exist as soon asinput
gets overwritten or ceases to exist [automatic-duration variables may cease to exist any time a compiler determines that their value will no longer be observed].If
CountThings
stores a copy of the reference somewhere that continues to exist after it returns, and the last extant reference is held by something other than a weak reference, then the object will cease to exist as soon as the last reference is destroyed.If the last existing reference the array ends up being held in a weak reference, the array will continue to exist until the first GC cycle where that is the case, whereupon the weak reference will be cleared, causing the array to cease to exist. Note that the lack of non-weak references to the array will only be relevant when a GC cycle occurs. It is possible (and not particularly uncommon) for a program to store a copy of a reference into a
WeakReference
,ConditionalWeakTable
, or other object holding some form of weak reference, destroy all other copies, and then read out the weak reference to produce a non-weak copy of the reference before the next GC cycle. If that occurs, the system will neither know nor care that there was a time when non non-weak copies of the reference existed. If the GC cycle occurs before the reference gets read out, however, then code which later examines the weak reference will find it blank.
A key observation is that while finalizers and weak references complicate things slightly, the only way in which the GC destroys objects is by invalidating weak forms of references. As far as the GC is concerned, the only kinds of storage that exist when the system isn't actually performing a GC cycle are those used by objects that exist, those used for .NET's internal purposes, and regions of storage that are available to satisfy future allocations. If an object is created, the storage it occupied will cease to be a region of storage available for future allocations. If the object later ceases to exist, the storage that had contained the object will also cease to exist in any form the GC knows about until the next GC cycle. The next GC cycle won't destroy the object (which had already ceased to exist), but will instead add the storage which had contained it back to its list of areas that are available to add future allocations (causing that storage to exist again).
add a comment |
up vote
1
down vote
No object can be garbage-collected while it is recognized as existing. An object will exist in .NET for as along as any reference to it exists or it has a registered finalizer, and will cease to exist once neither condition applies. References in objects will exist as long as the objects themselves exist, and references in automatic variables will exist as long as there is any means via which they will be observed. If the garbage collector detects that the only references to an object with no registered finalizer are held in weak references, those references will be destroyed, causing the object to cease to exist. If the garbage collector detects that the only references to an object with a registered finalizer are held in weak references, any weak references whose "track resurrection" property is false, a reference to the object will be placed in a strongly-rooted list of objects needing "immediate" finalization, and the finalizer will be unregistered (thus allowing it to cease to exist if and when the finalizer reaches a point in execution where no reference to the object could ever be observed).
Note that some sources confuse the triggering of an object's finalizer with garbage-collection, but an object whose finalizer is triggered is guaranteed to continue to exist for at least as long as that finalizer takes to execute, and may continue to exist indefinitely if any references to it exist when the finalizer finishes execution.
In your example, there are three scenarios that could apply, depending upon what CountThings
does with the passed-in reference:
If
CountThings
does not store a copy of the reference anywhere, or any copies of references that it does store get overwritten beforeinput
gets overwritten, then it will cease to exist as soon asinput
gets overwritten or ceases to exist [automatic-duration variables may cease to exist any time a compiler determines that their value will no longer be observed].If
CountThings
stores a copy of the reference somewhere that continues to exist after it returns, and the last extant reference is held by something other than a weak reference, then the object will cease to exist as soon as the last reference is destroyed.If the last existing reference the array ends up being held in a weak reference, the array will continue to exist until the first GC cycle where that is the case, whereupon the weak reference will be cleared, causing the array to cease to exist. Note that the lack of non-weak references to the array will only be relevant when a GC cycle occurs. It is possible (and not particularly uncommon) for a program to store a copy of a reference into a
WeakReference
,ConditionalWeakTable
, or other object holding some form of weak reference, destroy all other copies, and then read out the weak reference to produce a non-weak copy of the reference before the next GC cycle. If that occurs, the system will neither know nor care that there was a time when non non-weak copies of the reference existed. If the GC cycle occurs before the reference gets read out, however, then code which later examines the weak reference will find it blank.
A key observation is that while finalizers and weak references complicate things slightly, the only way in which the GC destroys objects is by invalidating weak forms of references. As far as the GC is concerned, the only kinds of storage that exist when the system isn't actually performing a GC cycle are those used by objects that exist, those used for .NET's internal purposes, and regions of storage that are available to satisfy future allocations. If an object is created, the storage it occupied will cease to be a region of storage available for future allocations. If the object later ceases to exist, the storage that had contained the object will also cease to exist in any form the GC knows about until the next GC cycle. The next GC cycle won't destroy the object (which had already ceased to exist), but will instead add the storage which had contained it back to its list of areas that are available to add future allocations (causing that storage to exist again).
add a comment |
up vote
1
down vote
up vote
1
down vote
No object can be garbage-collected while it is recognized as existing. An object will exist in .NET for as along as any reference to it exists or it has a registered finalizer, and will cease to exist once neither condition applies. References in objects will exist as long as the objects themselves exist, and references in automatic variables will exist as long as there is any means via which they will be observed. If the garbage collector detects that the only references to an object with no registered finalizer are held in weak references, those references will be destroyed, causing the object to cease to exist. If the garbage collector detects that the only references to an object with a registered finalizer are held in weak references, any weak references whose "track resurrection" property is false, a reference to the object will be placed in a strongly-rooted list of objects needing "immediate" finalization, and the finalizer will be unregistered (thus allowing it to cease to exist if and when the finalizer reaches a point in execution where no reference to the object could ever be observed).
Note that some sources confuse the triggering of an object's finalizer with garbage-collection, but an object whose finalizer is triggered is guaranteed to continue to exist for at least as long as that finalizer takes to execute, and may continue to exist indefinitely if any references to it exist when the finalizer finishes execution.
In your example, there are three scenarios that could apply, depending upon what CountThings
does with the passed-in reference:
If
CountThings
does not store a copy of the reference anywhere, or any copies of references that it does store get overwritten beforeinput
gets overwritten, then it will cease to exist as soon asinput
gets overwritten or ceases to exist [automatic-duration variables may cease to exist any time a compiler determines that their value will no longer be observed].If
CountThings
stores a copy of the reference somewhere that continues to exist after it returns, and the last extant reference is held by something other than a weak reference, then the object will cease to exist as soon as the last reference is destroyed.If the last existing reference the array ends up being held in a weak reference, the array will continue to exist until the first GC cycle where that is the case, whereupon the weak reference will be cleared, causing the array to cease to exist. Note that the lack of non-weak references to the array will only be relevant when a GC cycle occurs. It is possible (and not particularly uncommon) for a program to store a copy of a reference into a
WeakReference
,ConditionalWeakTable
, or other object holding some form of weak reference, destroy all other copies, and then read out the weak reference to produce a non-weak copy of the reference before the next GC cycle. If that occurs, the system will neither know nor care that there was a time when non non-weak copies of the reference existed. If the GC cycle occurs before the reference gets read out, however, then code which later examines the weak reference will find it blank.
A key observation is that while finalizers and weak references complicate things slightly, the only way in which the GC destroys objects is by invalidating weak forms of references. As far as the GC is concerned, the only kinds of storage that exist when the system isn't actually performing a GC cycle are those used by objects that exist, those used for .NET's internal purposes, and regions of storage that are available to satisfy future allocations. If an object is created, the storage it occupied will cease to be a region of storage available for future allocations. If the object later ceases to exist, the storage that had contained the object will also cease to exist in any form the GC knows about until the next GC cycle. The next GC cycle won't destroy the object (which had already ceased to exist), but will instead add the storage which had contained it back to its list of areas that are available to add future allocations (causing that storage to exist again).
No object can be garbage-collected while it is recognized as existing. An object will exist in .NET for as along as any reference to it exists or it has a registered finalizer, and will cease to exist once neither condition applies. References in objects will exist as long as the objects themselves exist, and references in automatic variables will exist as long as there is any means via which they will be observed. If the garbage collector detects that the only references to an object with no registered finalizer are held in weak references, those references will be destroyed, causing the object to cease to exist. If the garbage collector detects that the only references to an object with a registered finalizer are held in weak references, any weak references whose "track resurrection" property is false, a reference to the object will be placed in a strongly-rooted list of objects needing "immediate" finalization, and the finalizer will be unregistered (thus allowing it to cease to exist if and when the finalizer reaches a point in execution where no reference to the object could ever be observed).
Note that some sources confuse the triggering of an object's finalizer with garbage-collection, but an object whose finalizer is triggered is guaranteed to continue to exist for at least as long as that finalizer takes to execute, and may continue to exist indefinitely if any references to it exist when the finalizer finishes execution.
In your example, there are three scenarios that could apply, depending upon what CountThings
does with the passed-in reference:
If
CountThings
does not store a copy of the reference anywhere, or any copies of references that it does store get overwritten beforeinput
gets overwritten, then it will cease to exist as soon asinput
gets overwritten or ceases to exist [automatic-duration variables may cease to exist any time a compiler determines that their value will no longer be observed].If
CountThings
stores a copy of the reference somewhere that continues to exist after it returns, and the last extant reference is held by something other than a weak reference, then the object will cease to exist as soon as the last reference is destroyed.If the last existing reference the array ends up being held in a weak reference, the array will continue to exist until the first GC cycle where that is the case, whereupon the weak reference will be cleared, causing the array to cease to exist. Note that the lack of non-weak references to the array will only be relevant when a GC cycle occurs. It is possible (and not particularly uncommon) for a program to store a copy of a reference into a
WeakReference
,ConditionalWeakTable
, or other object holding some form of weak reference, destroy all other copies, and then read out the weak reference to produce a non-weak copy of the reference before the next GC cycle. If that occurs, the system will neither know nor care that there was a time when non non-weak copies of the reference existed. If the GC cycle occurs before the reference gets read out, however, then code which later examines the weak reference will find it blank.
A key observation is that while finalizers and weak references complicate things slightly, the only way in which the GC destroys objects is by invalidating weak forms of references. As far as the GC is concerned, the only kinds of storage that exist when the system isn't actually performing a GC cycle are those used by objects that exist, those used for .NET's internal purposes, and regions of storage that are available to satisfy future allocations. If an object is created, the storage it occupied will cease to be a region of storage available for future allocations. If the object later ceases to exist, the storage that had contained the object will also cease to exist in any form the GC knows about until the next GC cycle. The next GC cycle won't destroy the object (which had already ceased to exist), but will instead add the storage which had contained it back to its list of areas that are available to add future allocations (causing that storage to exist again).
answered Nov 8 at 17:09
supercat
55.5k2114146
55.5k2114146
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53211655%2fwhen-an-array-is-subject-to-garbage-collection%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
So... you're just having doubts about the accepted answer in that question you linked?
– Broots Waymb
Nov 8 at 16:09
@Broots Waymb I have a doubt between after the CountThings call and the null assignment
– Ehouarn Perret
Nov 8 at 16:10
1
After the CountThings call the value is still referenced - unless the compiler picks it up and refactors it somehow, I'd say that GC won't touch that value before null assignment.
– Szab
Nov 8 at 16:11
4
i would say its subject to GC before the line of
input = null
if the compiler is smart enough. If you are wondering about whether you need to assign it to null to help GC then the answer is no. absolutely not necessary– Steve
Nov 8 at 16:11
@Steve how can we find this out? I am thinking maybe checking the IL code maybe if the null is not "translated" then that means that this assignment is not needed to make it subject to garbage collection. I am not sure "how dumb" the compiler is.
– Ehouarn Perret
Nov 8 at 16:14