10.9 Automatic memory management

王朝other·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

10.9 Automatic memory management

C# employs automatic memory management, which frees developers from manually

allocating and freeing

the memory occupied by objects. Automatic memory management policies are

implemented by a garbage

collector. The memory management life cycle of an object is as follows:

1. When the object is created, memory is allocated for it, the constructor

is run, and the object is

considered live.

2. If the object, or any part of it, cannot be accessed by any possible

continuation of execution, other than

the running of destructors, the object is considered no longer in use, and

it becomes eligible for

destruction. [Note: Implementations may choose to analyze code to determine

which references to an

object may be used in the future. For instance, if a local variable that is

in scope is the only existing

reference to an object, but that local variable is never referred to in any

possible continuation of

execution from the current execution point in the procedure, an

implementation may (but is not required

to) treat the object as no longer in use. end note]

3. Once the object is eligible for destruction, at some unspecified later

time the destructor (§17.12) (if any)

for the object is run. Unless overridden by explicit calls, the destructor

for the object is run once only.

4. Once the destructor for an object is run, if that object, or any part of

it, cannot be accessed by any

possible continuation of execution, including the running of destructors,

the object is considered

inaccessible and the object becomes eligible for collection.

5. Finally, at some time after the object becomes eligible for collection,

the garbage collector frees the

memory associated with that object.

The garbage collector maintains information about object usage, and uses

this information to make memory

management decisions, such as where in memory to locate a newly created

object, when to relocate an

object, and when an object is no longer in use or inaccessible.

Like other languages that assume the existence of a garbage collector, C#

is designed so that the garbage

collector may implement a wide range of memory management policies. For

instance, C# does not require

that destructors be run or that objects be collected as soon as they are

eligible, or that destructors be run in

any particular order, or on any particular thread.

The behavior of the garbage collector can be controlled, to some degree,

via static methods on the class

System.GC. [Note: While not required by this specification, a Collect

method may be provided on the GC

class which requests that a collection be performed. The following examples

presume the existence of such

a method. end note]

[Example: Since the garbage collector is allowed wide latitude in deciding

when to collect objects and run

destructors, a conforming implementation may produce output that differs

from that shown by the following

code. The program

using System;

class A

{

~A() {

Console.WriteLine("Destruct instance of A");

}

}

C# LANGUAGE SPECIFICATION

86

class B

{

object Ref;

public B(object o) {

Ref = o;

}

~B() {

Console.WriteLine("Destruct instance of B");

}

}

class Test

{

static void Main() {

B b = new B(new A());

b = null;

GC.Collect();

GC.WaitForPendingFinalizers();

}

}

creates an instance of class A and an instance of class B. These objects

become eligible for garbage

collection when the variable b is assigned the value null, since after this

time it is impossible for any userwritten

code to access them. The output could be either

Destruct instance of A

Destruct instance of B

or

Destruct instance of B

Destruct instance of A

because the language imposes no constraints on the order in which objects

are garbage collected.

In subtle cases, the distinction between .eligible for destruction. and

.eligible for collection. can be

important. For example,

using System;

class A

{

~A() {

Console.WriteLine("Destruct instance of A");

}

public void F() {

Console.WriteLine("A.F");

Test.RefA = this;

}

}

class B

{

public A Ref;

~B() {

Console.WriteLine("Destruct instance of B");

Ref.F();

}

}

class Test

{

public static A RefA;

public static B RefB;

static void Main() {

RefB = new B();

RefA = new A();

RefB.Ref = RefA;

RefB = null;

RefA = null;

Chapter 10 Basic concepts

87

// A and B now eligible for destruction

GC.Collect();

GC.WaitForPendingFinalizers();

// B now eligible for collection, but A is not

if (RefA != null)

Console.WriteLine("RefA is not null");

}

}

In the above program, if the garbage collector chooses to run the

destructor of A before the destructor of B,

then the output of this program might be:

Destruct instance of A

Destruct instance of B

A.F

RefA is not null

Note that although the instance of A was not in use and A’s destructor was

run, it is still possible for methods

of A (in this case, F) to be called from another destructor. Also, note

that running of a destructor may cause

an object to become usable from the mainline program again. In this case,

the running of B’s destructor

caused an instance of A that was previously not in use to become accessible

from the live reference RefA.

After the call to WaitForPendingFinalizers, the instance of B is eligible

for collection, but the instance

of A is not, because of the reference RefA.

To avoid confusion and unexpected behavior, it is generally a good idea for

destructors to only perform

cleanup on data stored in their object’s own fields, and not to perform

any actions on referenced objects or

static fields. end example]

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有  導航