Interaction between types, objects, thread stacks, and managed stacks during runtime

Source: Internet
Author: User
Tags class manager

This section describes the relationships between types, objects, thread stacks, and managed stacks at runtime. It also explains the differences between calling static methods, instance methods, and virtual methods.

Assume there are two class definitions:

Internal class Employee

{

Public Int32 GetYearsEmployed (){...}

Public virtual string GetProgressReport (){...}

Public static Employee Lookup (string name ){...}

}

Internal sealed class Manager: Employee

{

Public override string GetProgressReport (){...}

}

The windows process has been started, the CLR has been loaded to it, the managed heap has been initialized, and a thread has been created (along with its 1 MB stack space ). This thread has executed some code and now calls the M3 method immediately. Shows the current situation. The Code contained in the M3 method demonstrates how the CLR works. It is not usually written because they do nothing really useful.

When the JIT compiler converts M3 IL code to local CPU commands, it will notice all types referenced in M3: Employee, Int32, Manager, and String (because "Joe "). At this time, the CLR should ensure that all the assemblies that define these types have been loaded. Then, using the Assembly metadata, CLR extracts information related to these types and creates some data structures to represent the types themselves. Shows the data structure used for objects of the Employee and Manager types. Since this thread has executed some code before calling M3, it is assumed that Int32 and String type objects have been created, so they are not shown in the figure.

Let's take a moment to discuss these types of objects. As mentioned earlier in this chapter, all objects on the stack contain two additional members: type object pointer and sync block index )., Both the Employee and Manager objects have these two members. When defining a type, you can define static data fields within the type. The bytes that support these static data fields are allocated in the type object itself. Each type object contains a method table. In the method table, each method defined in the type has a corresponding record item. We have discussed this method table in Chapter 1. Since the Employee type defines three methods, the Employee method table has three record items. Only one method is defined for the Manager type, so there is only one record in the Manager method table.

Now, when the CLR determines that all types of objects required by the method have been created and the M3 code has been compiled, the thread can start to execute the local code of the M3. During code execution of M3, memory must be allocated for local variables in the thread stack, as shown in Figure 4-8. By the way, as part of the method's "prelude" code, CLR will automatically Initialize all local variables to null or 0 (zero ). However, if you try to read data from a local variable that has not been explicitly initialized, C # reports an error message: the unassigned local variable is used.

Then, M3 executes its code to construct a Manager object. This creates a Manager instance (a Manager object) in the managed heap, as shown in Figure 4-9. As you can see, like all objects, the Manager object also has a type object pointer and a synchronized block index. This Object also contains necessary bytes to accommodate all instance data fields defined by the Manager type and all instance fields defined by any base class of the Manager (in this example, the Employee and Object. When a new object is created on the heap, CLR will automatically initialize the internal type object pointer member so that it can reference the type object corresponding to the object (in this example, the Manager type object ). In addition, CLR initializes the synchronization block index and sets all instance fields of the object to null or 0 (zero ), call the constructor of the type (it is essentially a method that may modify some instance data fields ). The new operator returns the memory address of the Manager object, which is saved in variable e (e on the thread stack ).

The next line of M3 code calls the static Lookup method of Employee. When a static method is called, CLR locates the type object corresponding to the type that defines the static method. Then, the JIT compiler searches for the record items corresponding to the called method in the method table of the type object, compiles the method with JIT (if necessary), and then calls the Code Compiled by JIT. In this example, we assume that the Lookup method of Employee needs to query a database to find Joe. In addition, if the database points out that Joe is a Manager of the company, The Lookup method constructs a new Manager object on the stack and initializes it with the information of Joe, then return the address of the object. This address is saved to the local variable e. The result of this operation is 4-10.

Note that e no longer references the first Manager object. In fact, since there is no variable to reference this object, it is the main target for future garbage collection. The garbage collection mechanism automatically recycles (releases) the memory occupied by this object.

The next line of code of M3 calls the non-virtual instance method GetYearsEmployed of Employee. When you call a non-real-world sample method, the JIT compiler will find the type object (Employee type object) corresponding to the "type of the variable (e) that calls the call ). In this example, variable e is defined as an Employee. If the Employee type does not define the method being called, the JIT compiler will trace back the class hierarchy (always back to the Object) and search for the method in each type along the way. The reason for this backtracking is that each type object has a field that references its base type, which is not shown in the figure.

Then, the JIT compiler searches for record items that reference the called method in the method table of the type object, compiles the method with JIT (if needed), and then calls the Code Compiled by JIT. In this example, assume that the GetYearsEmployed method of Employee returns 5 because Joe has been hired by the company for five years. This integer is stored in the local variable year. The result of this operation is 4-11.

The next line of code of M3 calls GenProgressReport of the actual sample method of Employee. When calling a real-world sample method, the JIT compiler must generate some additional code in the method. The code is executed every time the method is called. The code first checks the variables that make the call, and then follows the address to the object that sends the call. In this example, variable e references a Manager object that represents "Joe. Then, the code checks the "type Object Pointer" member inside the object, which points to the actual type of the object. Then, the Code searches for record items that reference the called method in the method table of the type object, compiles the method with JIT (if needed), and then calls the Code Compiled by JIT. In this example, because e references a Manager object, the GenProgressReport Implementation of Manager is called. The result of this operation is 4-12.

Note: If the Lookup method of Employee finds that Joe is only an Employee rather than a Manager, Lookup constructs an Employee object internally and its type object pointer references the Employee type object. In this way, the final execution is the implementation of the GenProgressReport of the Employee, rather than the implementation of the GenProgressReport of the Manager.

So far, we have discussed the relationship between source code, IL, and JIT compiled code. It also discusses the thread stack, real parameters, local variables, and how these real parameters and variables reference objects hosted on the stack. We also know that the object contains a pointer pointing to the object type object (the type object contains static fields and method tables ). We also discussed how the JIT compiler decides the call methods of static methods, non-Virtual-real examples, and virtual-real examples. After understanding all this, you can deeply understand the way CLR works. In the future, this knowledge will be of great help in the construction, design and implementation of types, components and applications. Before finishing this chapter, let's take a deeper look at what happens inside CLR.

Note that both the Employee and Manager objects contain "type Object Pointer" members. This is because the type object is essentially an object. When creating a type object, CLR must initialize these members. What is initialization? When CLR starts running in a process, it immediately creates a special Type object for the System. Type defined in MSCorLib. dll. The Employee and Manager types are all "instances" of this type ". Therefore, their Type object pointer members are initialized to reference System. Type objects, as shown in Figure 4-13.

Of course, the System. Type object itself is also an object, and there is also a member of the "Type Object Pointer. So what is this pointer pointing? It points to itself, because the System. Type object itself is an "instance" of a Type object ". Now we understand the entire type system of CLR and how it works. By the way, the GetType method of System. Object returns the address stored in the "type Object Pointer" member of the specified Object. In other words, the GetType method returns a pointer to the object type object. In this way, you can determine the real type of any object in the system (including the type object itself.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.