参考文章:
https://www.zditect.com/article/59283897.html
https://www.cnblogs.com/simonLiang/p/5729649.html
程序所有的数据,也就是所有的变量,都是存储在内存中的。
可编程内存基本上分为几大部分:栈区、堆区和静态存储区。
栈(stack)
保存局部变量和局部函数的,函数结束,其局部变量和参数的生命就结束了(当然是不包括static变量)。即释放了栈的空间(顺便提一下:栈特点为后进先出的!)。
栈的分配运算内置于处理器的指令集中,效率极高,但是分配的内存容量有限。
栈的特征:
数据只能从栈的顶端插⼊和删除
把数据放⼊栈顶称为⼊栈(push) 、
从栈顶删除数据称为出栈(pop)
内存中的栈,是由系统管理(.Net框架)。
堆(heap)
也称动态内存分配区。
堆是⼀块内存区域,与栈不同,堆⾥的内存能够以任意顺序存⼊和移除
程序员向操作系统申请的内存空间。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或delete释放内存。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。可存储较大的数据。
堆是以匿名方式保存的,只能通过指针访问,安全性最高,由程序员分配与释放,自由度最高!
GC Garbage Collector垃圾回收器
CLR的GC就是内存管理机制,我们写程序不需要关⼼内存的使⽤,因为这些都是CLR帮 我们做了
静态存储区
内存在程序编译的时候已经分配好。这块内存在整个程序的运行期间都存在。
主要存放静态数据、全局数据和常量。
堆栈的不同
(1)内存申请方式的不同:如果函数中声明一个局部变量int a,系统会自动在栈中为a 开辟空间;而堆空间需要程序员自己申请,还需要指明变量的大小。
(2)系统响应的不同:只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则提示overflow,栈溢出;而对于堆,系统在收到申请空间的要求后,遍历操作系统用于记录内存空间地址的链表,当找到一个空间大于所申请空间的堆结点后,就会将该结点从记录内存空闲地址的链表中删除。并将该结点的内存分配给程序,然后在这块内存区域的首地址处记录分配的大小。这样在使用delete来释放的时候,delete才能正确识别并删除该内存区域的所有变量。另外,申请的内存空间与堆结点的内存空间不一定相等,这是系统个会自动将堆结点上多出来的那一部分内存空间回收到空闲链表中。
(3)空间大小的不同:栈是一块连续的区域,大小在编译时就确定的常数,有系统预先根据栈顶的地址和栈的最大容量定义好的;堆是不连续的区域,各块区域由链表串联起来。串联起来的内存空间叫作堆!上限是由系统的虚拟内存来定的。
(4)执行效率的不同:栈比较快,由系统自动分批;堆速度较慢,且容易产生内存碎片。
(5)执行函数时的不同:函数调用时,第一个进栈的是被调函数下一行的内存地址(栈的先进后出)。其次是函数的参数,假如参数duo与一个,那么次序是从右往左。最后才是函数的局部变量。
栈空间⽐较⼩,但是读取速度快
堆空间⽐较⼤,但是读取速度慢
数组存储在c#中的堆或堆栈中
c#中对象是如何存储在内存中的
关于栈stack常用的方法
Stack<T>
堆栈(Stack)代表了一个后进先出的对象集合。
当您需要对各项进行后进先出的访问时,则使用堆栈。
当您在列表中添加一项,称为推入元素,当您从列表中移除一项时,称为弹出元素。
Stack是一种特殊的集合类型,
以LIFO方式(后进先出)存储元素。
C#包括泛型Stack<T>和非泛型Stack集合类。
建议使用泛型Stack<T>集合。
Stack 类的方法和属性
属性
Count (获取 Stack 中包含的元素个数。)
方法
public virtual void Clear();
从 Stack 中移除所有的元素。
public virtual bool Contains( object obj );
判断某个元素是否在 Stack 中。
public virtual object Peek();
返回在 Stack 的顶部的对象,但不移除它。
public virtual object Pop();
移除并返回在 Stack 的顶部的对象。
public virtual void Push( object obj );
向 Stack 的顶部添加一个对象。
public virtual object[] ToArray();
复制 Stack 到一个新的数组中。
下面的实例演示了堆栈(Stack)的使用:
创建堆栈
Stack<int> myStack = new Stack<int>(); myStack.Push(1); myStack.Push(2); myStack.Push(3); myStack.Push(4); foreach (var item in myStack) Console.Write(item + ","); //打印4,3,2,1,
使用示例:
using System; using System.Collections; namespace CollectionsApplication { class Program { static void Main(string[] args) { Stack st = new Stack(); st.Push('A'); st.Push('M'); st.Push('G'); st.Push('W'); Console.WriteLine("Current stack: "); foreach (char c in st) { Console.Write(c + " "); } Console.WriteLine(); st.Push('V'); st.Push('H'); Console.WriteLine("The next poppable value in stack: {0}", st.Peek()); Console.WriteLine("Current stack: "); foreach (char c in st) { Console.Write(c + " "); } Console.WriteLine(); Console.WriteLine("Removing values "); st.Pop(); st.Pop(); st.Pop(); Console.WriteLine("Current stack: "); foreach (char c in st) { Console.Write(c + " "); } } } }
关于队列Queue的属性常用方法
System.Collections.Queue类表示对象的先进先出集合,存储在 Queue(队列) 中的对象在一端插入,从另一端移除。
Queue队列就是先进先出。它并没有实现 IList,ICollection。所以它不能按索引访问元素,不能使用Add和Remove。下面是 Queue的一些方法
- Enqueue():在队列的末端添加元素
- Dequeue():在队列的头部读取和删除一个元素,注意,这里读取元素的同时也删除了这个元素。如果队列中不再有任何元素。就抛出异常
- Peek():在队列的头读取一个元素,但是不删除它
- TrimExcess():重新设置队列的容量,因为调用Dequeue方法读取删除元素后不会重新设置队列的容量。
- Contains():确定某个元素是否在队列中
- CopyTo():把元素队列复制到一个已有的数组中
- ToArray():返回一个包含元素的新数组
属性
- Count:返回队列中的元素个数
使用示例:
class Program { static void Main(string[] args) { //创建一个队列 Queue myQ = new Queue(); myQ.Enqueue("The");//入队 myQ.Enqueue("quick"); myQ.Enqueue("brown"); myQ.Enqueue("fox"); myQ.Enqueue(null);//添加null myQ.Enqueue("fox");//添加重复的元素 // 打印队列的数量和值 Console.WriteLine("myQ"); Console.WriteLine("\tCount: {0}", myQ.Count); // 打印队列中的所有值 Console.Write("Queue values:"); PrintValues(myQ); // 打印队列中的第一个元素,并移除 Console.WriteLine("(Dequeue)\t{0}", myQ.Dequeue()); // 打印队列中的所有值 Console.Write("Queue values:"); PrintValues(myQ); // 打印队列中的第一个元素,并移除 Console.WriteLine("(Dequeue)\t{0}", myQ.Dequeue()); // 打印队列中的所有值 Console.Write("Queue values:"); PrintValues(myQ); // 打印队列中的第一个元素 Console.WriteLine("(Peek) \t{0}", myQ.Peek()); // 打印队列中的所有值 Console.Write("Queue values:"); PrintValues(myQ); Console.ReadLine(); } public static void PrintValues(IEnumerable myCollection) { foreach (Object obj in myCollection) Console.Write(" {0}", obj); Console.WriteLine(); } }