一、System.Object
运行时要求每个类型最终都要从System.Object
派生,它提供了如下几个基本方法:
方法名 | 说明 |
---|---|
Equals() |
虚方法。两个对象具有相同的值,就返回true |
GetHashCode() |
虚方法。返回对象的哈希码 |
ToString() |
虚方法。默认返回类型的完整名称 |
GetType() |
非虚方法。指出对象是什么类型 |
MemberwiseClone() |
非虚方法。创建该类型的新实例,且其实例字段与this 的实例字段完全一致 |
Finalize() |
虚方法。在对象内存被回收之前会被调用 |
CLR要求所有的对象都用new
操作符创建。比如:
Apple apple = new Apple();
在这期间,new
操作符其实做了以下几件事情:
- 计算类型及其所有基类型中定义的所有实例字段所需的字节数。此外,还需要加上一些额外的成员所占的字节数,包括:类型对象指针、同步块索引,还有一个未公开的内部字段(用于计算对象实例的哈希值)。
- 从托管堆中分配计算好的字节数的内存,并且所有的二进制位都初始化为0。
- 初始化对象的“类型对象指针”和“同步块索引”。
- 调用类型的构造器,传递指定的实参。每个类型的构造器都负责初始化自己的实例字段。最终会调用到
System.Object
的构造器,并返回。
new
执行完这些操作后,会返回指向新建对象的一个引用。
上面有几个名词需要解释一下:
实例字段:指非静态字段,是属于对象的。与之相对的静态字段是属于类的。
类型对象指针:每个对象都是一个类型的实例,而每个类型都由一个Type
类型的实例来表示。类型对象指针就是指向该Type
实例的指针。当然,Type
类型对象本身也是一个类型对象的实例,它的类型对象指针指向了它自己。
同步块索引:可以简单理解为一个指向“同步块”的指针,拥有这个同步块的对象可以支持线程同步。
二、线程栈
线程创建时会分配1MB
的栈。栈空间用来向方法传递实参,方法内部定义的局部变量也存在栈上。栈从高位内存地址向低位内存地址构建。
假如线程要调用下面的M1
方法:
void M1()
{
string name = "Joe";
M2(name);
// ...
return;
}
void M2