b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

提高程序性能,理解和堆,必须就栈的大小有明确定义

电脑杂谈  发布时间:2021-05-07 10:00:48  来源:网络整理

谈论C#中堆和堆栈之间的区别(带有图表)

更新时间:2014年9月18日09:01:35贡献:hebedich

C#中的堆栈是在编译期间分配的内存空间,因此您的代码必须对堆栈的大小有清晰的定义。堆是程序运行时动态分配的内存空间,可以根据程序的运行状态来确定。要分配的堆内存大小

线程堆栈:称为堆栈堆栈

托管堆:简称堆

使用.Net框架开发程序时,我们不需要关心内存分配问题,因为大型管家GC会为我们处理所有事情。如果我们编写以下两段代码:

代码段1:

public int AddFive(int pValue)
{
int result;
result = pValue + 5;
return result;
}

代码段2:

public class MyInt
{ 
public int MyValue;
}
public MyInt AddFive(int pValue)
{
MyInt result = new MyInt();
result.MyValue = pValue + 5;
return result;
}

问题1:执行代码段1时,您知道pValue和结果如何存储在内存中吗?生命周期是多少?代码片段2呢?

为了解释上述问题,我们应该对堆栈和下面的托管堆(堆)(称为堆)有一个清晰的了解。如果要提高程序性能,则必须了解堆栈和堆!

本文将从堆栈,堆和类型变量开始,并分析我们编写的程序。

当C#程序在CLR上运行时,该存储器在逻辑上分为两个块:堆栈和堆。这两个基本元素构成了我们的C#程序的操作环境。

一,堆与堆:区别?

堆栈通常存储我们的代码执行的步骤,例如代码段1中的AddFive()方法,int pValue变量,int result变量等。另一方面,对象和数据大部分存储在堆。 (译者注:忽略编译器优化)我们可以将堆栈视为一个接一个地堆叠的盒子。使用它时,我们一次从顶部删除一个框。堆栈也是如此。当一个方法(或类型)被调用时,它是从栈顶(称为框架)开始,然后是下一个。堆不是这样。它就像一个仓库,其中存储了各种物品和我们使用的其他信息。与堆栈不同,它们在被调用后不会立即被清除。

图1,堆栈和堆的

(ͼ1)

堆栈内存不需要由我们管理,也不需要由GC管理。当堆栈的顶部元素用完时,将立即释放它。堆需要GC(垃圾收集:垃圾收集器)进行清理。

第二,将什么元素分配给堆栈?什么分配给堆?

执行程序时,堆栈和堆中分配了四种主要类型:值类型,引用类型,指针和指令。

值类型:

在C#中,从System.ValueType继承的类型称为值类型,主要有以下类型(在CLR 2. 0中支持的类型有所增加):

* bool

*字节

*字符

*小数点

c#堆和栈和内存的关系_c#堆和栈和内存的关系_java中栈内存和堆内存

*两倍

*枚举

*浮动

* int

*长

*字节

*短

*结构

* uint

*乌龙

* ushort

引用类型:

以下是从System.Object继承的引用类型:

*班级

*界面

*代表人

*对象

*字符串

指针:

在存储区中,对类型(通常称为“指针”)的引用由CLR(公共语言运行时)管理,我们无法显示它。应该注意的是,引用的类型(即指针)和引用的类型是两个完全不同的概念。指针占据了内存中的一个内存区域,它仅代表一个内存地址(或空值),而它指向的另一个内存区域就是我们的真实数据或类型。如图2所示:

(ͼ2)

命令:

说明将在以后介绍。

三,如何分配?

首先让我们看两点:

视图1,引用类型始终在堆上分配。 (正确吗?)

观点2,值类型和指针始终分配在定义它们的位置,它们不一定在堆栈上分配。 (这有点难以理解,您需要花点时间)

上面提到的堆栈,在程序运行时,每个线程(线程)都维护自己的专用线程堆栈。

调用方法时,主线程开始在其自己的程序集的元数据中找到被调用的方法,然后通过JIT快速对其进行编译,并将结果(通常是本地CPU指令)放在堆栈。 CPU通过总线从堆栈的顶部获取指令,驱动程序执行该指令。

下面通过示例详细讨论它。

我们在开头列出的摘录1:

public int AddFive(int pValue)
{
int result;
result = pValue + 5;
return result;
}

当AddFive方法开始执行时,方法参数(参数)将分配到堆栈中。如图3所示:

(ͼ3)

注意:该方法不存在于堆栈中,插图仅供参考。

接下来,该指令指向AddFive方法。如果是第一次执行该方法,则必须首先执行JIT即时编译。如图4所示:

(ͼ4)

当该方法开始在内部执行时,变量结果将分配到堆栈上,如图5所示:

(ͼ5)

该方法被执行,该方法返回,如图6所示:

(ͼ6)

执行该方法并返回后,将清除堆栈上的区域。如图7所示:

(ͼ7)

如上所述,通常在堆栈上分配一个值类型变量。您如何理解Viewpoint 2中的内容? “值类型和指针总是分配在定义它们的位置,而不必在堆栈上分配。”

原因是,如果在方法外部和引用类型中声明了值类型,则它将在堆上分配。

代码段2:

public class MyInt
{ 
public int MyValue;
}
public MyInt AddFive(int pValue)
{
MyInt result = new MyInt();
result.MyValue = pValue + 5;
return result;
}

当线程开始执行AddFive方法时,参数将分配到堆栈上,如图8所示:

(图片8)

由于MyInt是引用类型,因此将其分配在堆上,并在堆栈上生成一个指针(结果),如图9所示:

(图片9)

执行AddFive方法的情况如图10所示:

(ͼ10)

清除堆栈上的内存,并且堆仍然存在,如图11所示:

(ͼ11)

当程序需要更多的堆空间时,GC需要清理垃圾,挂起所有线程,查找所有无法访问的对象(即未引用的对象)并进行清理。并在地址排序后通知堆栈中的指针重新指向该对象。现在我们应该知道理解堆栈和堆对于我们开发高性能程序的重要性。当我们使用引用类型时,通常是对指针的操作,而不是引用类型对象本身。但是值类型可以自己操作。

接下来,我们将通过一个示例来说明这一点。

示例1:

public int ReturnValue()
{
int x = new int();
x = 3;
int y = new int();
y = x; 
y = 4; 
return x;
}

执行结果为3,略有修改:

示例2:

public class MyInt
{
public int MyValue;
}
public int ReturnValue2()
{
MyInt x = new MyInt();
x.MyValue = 3;
MyInt y = new MyInt();
y = x; 
y.MyValue = 4; 
return x.MyValue;
}

执行结果为4。

让我们分析原因。示例1与以下代码具有相同的效果:

public int ReturnValue()
{
int x = 3;
int y = x; 
y = 4;
return x;
}

如图12所示,x和y分别占据堆栈上的一个存储区域,并且不会互相干扰。

(图1 2)

在情况2中,它与以下代码具有相同的作用:

public int ReturnValue2()
{
MyInt x;
x.MyValue = 3;
MyInt y;
y = x; 
y.MyValue = 4;
return x.MyValue;
}

如图13所示,

(ͼ13)

堆栈上的指针x和y指向堆上的同一区域。修改其中之一肯定会更改堆上的数据。


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-373660-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      • 董金岳
        董金岳

        折腾能让我们尽加快实现统一祖国的愿望

      • 栗要兵
        栗要兵

        恬不知耻

      热点图片
      拼命载入中...