栈、托管堆、值类型、引用类型的理解

 

1. 托管堆与堆栈

托管堆:初始化新进程时,运行会为进程保留一个连续的地址空间区域,这个保留的地址空间称为托管堆。托管堆维护着一个指针,用它指向将在堆中分配的下一个对象的地址,最初,该指针设置为指向托管堆的基址。

托管代码:使用CLR的语言编译器开发的代码统称托管代码。

    △值类型直接存储基值,引用类型存储对值的引用,值类型存储在堆栈上,引用类型存储在托管堆上,值类型→引用类型(装箱),引用类型→值类型(拆箱)

 

堆栈与托管堆的工作方式:

C/C++中:

Stack叫做栈区,由编译器自动释放,存放函数的参数值,局部变量值等。

C#中:Stack是指栈区,Heap是指托管堆。

 

堆栈的工作方式:   

Int a=1;
Double b=1.1;

 

 

             图表 1未分配内存

 

 

    图表 2已分配内存后

 

 托管堆的工作方式:堆栈有非常高的性能,但要求变量生命周期必须嵌套(后进先出决定的),在很多情况下这种要求很过分,通常我们希望通过一个方法来分配内存,用来存储一些数据并在方法退出很久时间内数据任是可用的,用new运算符来请求控件,就实现了这种可能。

 

Void DoSomeThing()
{
    Customer John;→声明一个Customer的应用John,包含Customer对象的地址,需4字节
    Join=new Customer();→托管堆分配内存,假设对象占用了32个字节,.NET运行库关于在堆中搜索一块连续的未使用过的32个字节的控件,假定起始地址为200000
}

 

声明应用内存图解:

实例化对象内存图解:

★引用变量生存周期:只要堆栈中存在对它的引用,该变量就不会失效

2. 托管堆的垃圾回收机制

当对象不被引用时,会闪出堆中对应的数据,如果仅是这样,久而久之自由空间就会被分割开来,新对象需要分配内存时会很难处理,但托管堆垃圾回收器在运行时只要它释放能释放的对象,就将其他对象压缩,把他们推向堆的顶部,形成一个连续的块,虽看似造成性能损失,但给新对象分配内存提供了方便。

 

3. 装箱和拆箱

装箱过程:首先堆栈中分配一个字节的空间用来存储引用变量I。然后在托管堆中分配比之占空间的区域来存储它的拷贝,多了一个方法表指针和一个SyncBlockIndex,再把地址赋给I

拆箱过程:在堆栈分配的4个字节的控件来保存变量J,拷贝O的实例到J的内

 

代码:

{

int I=1;

object O=I;//装箱

int J=(int)O;拆箱

}

★拆箱注意:必须保证该值变量J有足够的空间来拆箱得到的值O

4. 值类型与引用类型的复制过程

代码:

 
public class Point//若为结构体 struct
{
public int x;
public int y;
}
Point p1=new Point();
p1.x=1;
p1.y=2;
 
Point p2=p1;
p2.x=3;
p2.y=4;
Console.WriteLine p1.x,p1.y,p2.x,p2.y;

 

结果:3434

结果:1234

 

图解:共同指向托管堆的存值区域

★故:改变p2的值会影响p1,若Point为结构体(Struct),复制地址的同时连同值也一同复制,故不影响。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-04-30 22:04  NCat  阅读(235)  评论(0)    收藏  举报