类型,对象,堆栈和托管堆

C#的类型和对象在应用计算机内存时,大体用到两种内存,一个叫堆栈,另一个叫托管堆,下面我们用直角长方形来代表堆栈,用圆角长方形来代表托管堆。

首先讨论一下方法内部变量的存放。

先举个例子,有如下两个方法,Method_1和Add,分别如下:

public void Method_1()

{

int value1=10;  //1

int value2=20;    //2

int value3=Add(value,value); //3

}

public int Add(int n1,int n2)//4

{

rnt sum=n1+n2;//5

return sum;//6

}

这段代码的执行,用图表示为:

上述的每个图片,基本对应程序中的每个步骤。在开始执行Method_1的时候,先把value1压入堆栈顶,然后是value2,接下来的是调用方法Add,因为方法有两个参数是n1和n2,所以把n1和n2分别压入堆栈,因为此处是调用了一个方法,并且方法有返回值,所以这里需要保存Add的返回地址,然后进入Add方法内部,在Add内部,首先是给sum赋值,所以把sum压入栈项,然后用return返回,此时,先前的返回地址就起到了作用,return会根据地址返回去的,在返回的过程中,把sum推出栈顶,找到了返回地址,但在Method_1方法中,我们希望把Add的返回值赋给value3,此时的返回地址也被推出堆栈,把value3压入堆栈。虽这个例子的结果在这里没有多大用途,但这个例子很好的说明了在方法被执行时,变量与进出堆栈的情况。这里也能看出为什么方法内部的局变量用过后,不能在其他方法中访问的原因。

其次来讨论一下类和对象在托管堆和堆栈中的情况。

先看一下代码:

class Car

{

public void Run()

{

Console.WriteLine("一切正常");

}

public virtual double GetPrice()

{

return 0;

}

public static void Purpose()

{

Console.WriteLine("载人");

}

}

class BMW : Car

{

public override double GetPrice()

{

return 800000;

}

}

上面是两个类,一个Father一个Son,Son继承了Father,因为你类中有一个virtual的BuyHouse方法,所以Son类可以重写这个方法。

下面接着看调用代码。

public void Method_A()

{

double CarPrice;//1

Car car = new BMW();//2

CarPrice = car.GetPrice();//调用虚方法(其实调用的是重写后的方法)

car.Run();//调用实例化方法

Car.Purpose();//调用静态方法

}

这个方法也比较简单,就是定义一个变量用来获得价格,同时定义了一个父类的变量,用子类来实例化它。

接下来,我们分步来说明。

看一下运行时堆栈和托管堆的情部我:

这里需要说明的是,类是位于托管堆中的,每个类又分为四个类部,类指针,用来关联对象;同步索引,用来完成同步(比如线程的同步)需建立的;静态成员是属于类的,所以在类中出现,还有一个方法列表(这里的方法列表项与具体的方法对应)。

当Method_A方法的第一步执行时:

这时的CarPrice是没有值的

当Method_A方法执行到第二步,其实第二步又可以分成

Car car;

car = new BMW();

先看Car car;

car在这里是一个方法内部的变量,所以被压到堆栈中。

再看 car = new BMW();

这是一个实例化过程,car变成了一个对象

这里是用子类来实例化父类型。对象其实是子类的类型的,但变量的类型是父类的。

接下来,在Method_A中的调用的中调用car.GetPrice(),对于Car来说,这个方法是虚方法(并且子类重写了它),虚方法在调用是不会执行类型上的方法,即不会执行Car类中的虚方法,而是执行对象对应类上的方法,即 BMW中的GtPrice。

如果Method_A中执行方法Run(),因为Run是普通实例方法,所以会执行Car类中的Run方法。

如果调用了Method_A的Purpose方法,即不用变量car调用,也不用对象调用,而是用类名Car调用,因为静态方法会在类中分配内存的。如果用Car生成多个实例,静态成员只有一份,就是在类中,而不是在对象中。

时间: 2024-12-18 20:09:25

类型,对象,堆栈和托管堆的相关文章

堆栈和托管堆 c#

堆栈和托管堆 c# 首先堆栈和堆(托管堆)都在进程的虚拟内存中.(在32位处理器上每个进程的虚拟内存为4GB) 堆栈stack 堆栈中存储值类型. 堆栈实际上是向下填充,即由高内存地址指向低内存地址填充. 堆栈的工作方式是先分配内存的变量后释放(先进后出原则). 堆栈中的变量是从下向上释放,这样就保证了堆栈中先进后出的规则不与变量的生命周期起冲突! 堆栈的性能非常高,但是对于所有的变量来说还不太灵活,而且变量的生命周期必须嵌套. 通常我们希望使用一种方法分配内存来存储数据,并且方法退出后很长一段

浅谈C#堆栈与托管堆的工作方式(转)

C#初学者经常被问的几道辨析题,值类型与引用类型,装箱与拆箱,堆栈,这几个概念组合之间区别,看完此篇应该可以解惑. 俗话说,用思想编程的是文艺程序猿,用经验编程的是普通程序猿,用复制粘贴编程的是2B程序猿,开个玩笑^_^. 相信有过C#面试经历的人,对下面这句话一定不陌生: 值类型直接存储其值,引用类型存储对值的引用,值类型存在堆栈上,引用类型存储在托管堆上,值类型转为引用类型叫做装箱,引用类型转为值类型叫拆箱. 但仅仅背过这句话是不够的. C#程序员不必手工管理内存,但要编写高效的代码,就仍需

C#堆栈和托管堆

首先堆栈和堆(托管堆)都在进程的虚拟内存中.(在32位处理器上每个进程的虚拟内存为4GB) 堆栈stack 堆栈中存储值类型. 堆栈实际上是向下填充,即由高内存地址指向低内存地址填充. 堆栈的工作方式是先分配内存的变量后释放(先进后出原则). 堆栈中的变量是从下向上释放,这样就保证了堆栈中先进后出的规则不与变量的生命周期起冲突! 堆栈的性能非常高,但是对于所有的变量来说还不太灵活,而且变量的生命周期必须嵌套. 通常我们希望使用一种方法分配内存来存储数据,并且方法退出后很长一段时间内数据仍然可以使

C#内存管理之托管堆与非托管堆( reprint )

在 .NET Framework 中,内存中的资源(即所有二进制信息的集合)分为“托管资源”和“非托管资源”.托管资源必须接受 .NET Framework 的 CLR (通用语言运行时)的管理(诸如内存类型安全性检查),而非托管资源则不必接受 .NET Framework 的 CLR 管理.(了解更多区别请参阅 .NET Framework 或 C# 的高级编程资料)托管资源在 .NET Framework 中又分别存放在两种地方:“堆栈”和“托管堆”(以下简称“堆”):规则是,所有的值类型(

.NET 托管堆和垃圾回收

托管堆基础 简述:每个程序都要使用这样或那样的资源,包括文件.内存缓冲区.屏幕空间.网络连接.....事实上,在面向对象的环境中,每个类型都代表可供程序使用的一种资源.要使用这些资源,必须为代表资源的类型分配内存.以下是访问一个资源所需步骤:1.调用IL指令newobj,为代表资源的类型分配内存.(C# new操作符)2.初始化内存,设置资源的初始状态.(一般指构造函数)3.访问类型的成员来使用资源.(使用成员变量.方法.属性等)4.摧毁资源的状态以进行清除.(???Dispose???)5.释

【C#进阶系列】20 托管堆和垃圾回收

托管堆基础 一般创建一个对象就是通过调用IL指令newobj分配内存,然后初始化内存,也就是实例构造器时做这个事. 然后在使用完对象后,摧毁资源的状态以进行清理,然后由垃圾回收器来释放内存. 托管堆除了能避免错误使用已经被释放的内存,也会减少内存泄漏,大多数类型都无需资源清理,垃圾回收器会自动释放资源. 当然也有需要立即清理的,比如一些包含了本机资源的类型(如文件.套接字和数据库连接等),可在这些类中调用一个Dispose方法.(当然有的类对这个方法封装了一下,可能是别的名字比如断开数据库连接的

C# 托管堆和垃圾回收器GC

这里我们讨论的两个东西:托管堆和垃圾回收器,前者是负责创建对象并控制这些对象的生存周期,后者负责回收这些对象. 一.托管堆分配资源 CLR要求所有的对象都从托管堆分配.进程初始化时,CLR划出一个地址空间区域作为托管堆.CLR还要维护一个指针P,该指针指向下一个对象在堆中的分配位置. 那么我们进一步深入看看创建一个对象(也就是new 一个对象)时CLR做了哪些工作呢. 1.计算类型字段需要的字节数. 2.加上对象开销所需要的字节数,每个对象都有两个开销:类型对象指针和同步块索引 3.CLR检查区

CLR via C#-托管堆和垃圾回收

托管堆基础 访问类型的资源 面向对象的环境中,每个类型都代表可供程序使用的一种资源.要使用这些资源,必须为代表资源的类型分配内存.以下是访问一个资源所需的步骤. ①调用IL指令newobj,为代表资源的类型分配内存,由new操作符来完成. ②初始化内存,设置资源的初始状态并使资源可用,类型的实例构造器负责设置初始状态. ③访问类型的成员来使用资源. ④摧毁资源的状态以进行清理. ⑤释放内存,垃圾回收器独自负责这一步. 托管堆为开发人员提供了一个简化的编程模型,分配并初始化资源并直接使用. 大多数

重温CLR(十五) 托管堆和垃圾回收

本章要讨论托管应用程序如何构造新对象,托管堆如何控制这些对象的生存期,以及如何回收这些对象的内存.简单地说,本章要解释clr中的垃圾回收期是如何工作的,还要解释相关的性能问题.另外,本章讨论了如何设计应用程序来最有效地使用内存. 托管堆基础 每个程序都要使用这样或那样的资源,包括文件.内存缓冲区.屏幕空间.网络连接.数据库资源等.事实上,在面向对象的环境中,每个类型都代表可提供程序使用的一种资源.要使用这些资源,必须为代表资源的类型分配内存.以下是访问一个资源所需的步骤 1 调用IL指令newo