c#静态方法和实例方法的内存分配问题
2011-12-16 22:08
357 查看
一直对实例方法的内存如何分配有很大疑惑(通俗的讲就是实例方法在内存中有几份),找了很多资料,以下是一个比较令我满意的答案,记录下:
方法 (Method) 是一种类型定义,所以,它被存放在 Type Object 上,Type Object 是一个被分配在托管堆上的特殊类型,在同一个 AppDomain 中,每一个类型,都对应一个全局的 Type Object。每个引用类型的实例,都包含一个指向它的直接类型的 Type Object 的指针,每个 Type Object 也存在类似的指针,用来标识它的直接父类型的 Type Object。
当调用静态方法时,CLR 会根据方法调用去寻找其对应的 Type Object,然后,把方法 JIT,JIT 之后的方法是本机代码,可以直接运行,然后,这部分代码被加载进入内存,方法的参数被加载进入当前执行栈,原来的执行上下文地址也被记录到执行栈;方法开始执行,执行完后,执行栈中的返回地址被读出,然后 CLR 利用本机跳转指令,跳转到该返回至继续执行。
当调用实例方法时,CLR 会根据实例的 Type Object 指针找到对应的 Type Object,然后,把方法 JIT,JIT 之后的方法是本机代码,可以直接运行,然后,这部分代码被加载进入内存,该实例对象,以及方法的参数被加载进入当前执行栈 (实例对象永远是第一个参数,即 arg0,利用 ldarg0 指令进行读取),原来的执行上下文地址也被记录到执行栈;方法开始执行,执行完后,执行栈中的返回地址被读出,然后 CLR 利用本机跳转指令,跳转到该返回至继续执行。
如果方法已经被 JIT 过,则不会被第二次 JIT。
方法在 IL 中是以字节流的形式存在的,所以,它仍然会占据内存。
方法 JIT 之后会被驻留在该进程的地址空间里面,因此,它也会在运行时占据内存。
方法的元数据存放在程序集 MethodRef 以及 MethodDef 表中。
定义在值类型上的实例方法就比较麻烦了,大家有兴趣可以想想它怎么执行的。因为值类型没有 Type Object 指针。
如果值类型实现一个接口,在执行接口的方法实现的时候就更加麻烦了,大家也可以想想,欢迎讨论!
最后,
大家都以为“ 静态方法在堆上分配内 存,实例方法在堆栈上”
这句话完全不靠谱,不要被迷惑了。。。只要提到方法,它就一定在 Type Object 上,也就是被分配在托管堆上。
总结下,不管是实例还是静态方法,被JIT只存在一份,不过实例方法多了一个引用该实例的参数作为它的第一个参数!
方法 (Method) 是一种类型定义,所以,它被存放在 Type Object 上,Type Object 是一个被分配在托管堆上的特殊类型,在同一个 AppDomain 中,每一个类型,都对应一个全局的 Type Object。每个引用类型的实例,都包含一个指向它的直接类型的 Type Object 的指针,每个 Type Object 也存在类似的指针,用来标识它的直接父类型的 Type Object。
当调用静态方法时,CLR 会根据方法调用去寻找其对应的 Type Object,然后,把方法 JIT,JIT 之后的方法是本机代码,可以直接运行,然后,这部分代码被加载进入内存,方法的参数被加载进入当前执行栈,原来的执行上下文地址也被记录到执行栈;方法开始执行,执行完后,执行栈中的返回地址被读出,然后 CLR 利用本机跳转指令,跳转到该返回至继续执行。
当调用实例方法时,CLR 会根据实例的 Type Object 指针找到对应的 Type Object,然后,把方法 JIT,JIT 之后的方法是本机代码,可以直接运行,然后,这部分代码被加载进入内存,该实例对象,以及方法的参数被加载进入当前执行栈 (实例对象永远是第一个参数,即 arg0,利用 ldarg0 指令进行读取),原来的执行上下文地址也被记录到执行栈;方法开始执行,执行完后,执行栈中的返回地址被读出,然后 CLR 利用本机跳转指令,跳转到该返回至继续执行。
如果方法已经被 JIT 过,则不会被第二次 JIT。
方法在 IL 中是以字节流的形式存在的,所以,它仍然会占据内存。
方法 JIT 之后会被驻留在该进程的地址空间里面,因此,它也会在运行时占据内存。
方法的元数据存放在程序集 MethodRef 以及 MethodDef 表中。
定义在值类型上的实例方法就比较麻烦了,大家有兴趣可以想想它怎么执行的。因为值类型没有 Type Object 指针。
如果值类型实现一个接口,在执行接口的方法实现的时候就更加麻烦了,大家也可以想想,欢迎讨论!
最后,
大家都以为“ 静态方法在堆上分配内 存,实例方法在堆栈上”
这句话完全不靠谱,不要被迷惑了。。。只要提到方法,它就一定在 Type Object 上,也就是被分配在托管堆上。
总结下,不管是实例还是静态方法,被JIT只存在一份,不过实例方法多了一个引用该实例的参数作为它的第一个参数!
相关文章推荐
- c#静态方法和实例方法的内存分配问题
- 今天发现c#中的实例后的对象是不能调用静态方法,以前学Java的时候是可以的.
- JAVA 堆栈 堆 方法区 静态区 final static 内存分配 详解
- 关于c#静态方法和实例方法的辨析和应用
- C# 使用 StructLayoutAttribute 时 C# /C++ 内存空间分配与成员对齐问题
- SQL服务器内存有两种基本管理方法:动态分配和静态分配
- 今天发现c#中的实例后的对象是不能调用静态方法,以前学Java的时候是可以的.
- JAVA 堆栈 堆 方法区 静态区 final static 内存分配 详解
- JAVA 堆栈 堆 方法区 静态区 final static 内存分配
- C#中File静态类及其常用静态方法实例详解
- C++内存分配的五种方法 与 c++内存问题
- 全局变量,静态全局变量,静态局部变量,类静态成员内存分配与初始化问题
- 关于c#静态方法和实例方法的辨析和应用
- C#静态方法与非静态方法实例分析
- 关于C#静态方法调用问题
- 关于C++和C#中的静态方法的问题!
- 请高手帮忙:C/C++内存分配的问题?实例求解
- c# Java 静态方法 并发问题
- SQL服务器内存有两种基本管理方法:动态分配和静态分配
- JAVA 堆栈 堆 方法区 静态区 final static 内存分配 详解