美文网首页
C# 中的栈和堆

C# 中的栈和堆

作者: 源小白 | 来源:发表于2018-09-21 13:42 被阅读24次

本文是《C# 图解教程》的笔记。

程序运行时,它的数据必须存储在内存中。一个数据项需要多大的内存、存储在什么地方、以及如何存储都依赖于该数据项的类型。

运行中的程序使用两个内存区域来存储数据:栈和堆。

栈是一个内存数组,是一个LIFO(Last-In First-Out,后进先出)的数据结构。栈存储几种类型的数据:

  • 某些类型变量的值
  • 程序当前的执行环境
  • 传递给方法的参数

系统管理所有的栈操作。作为程序员,你不需要显式地对它做任何事情。但了解栈的基本功能可以更好地了解程序在运行时正在做什么,并能更好地了解C#文档和著作。

image

堆是一块内存区域,在堆里可以分配大块的内存用于存储某类型的数据对象。与栈不同,堆里的内存能够以任意顺序存入和移除。图3-7展示了一个在堆里放了4项数据的程序。

image

虽然程序可以在堆里保存数据,但并不能显式地删除它们。CLR的自动GC(Garbage Collector,垃圾收集器)在判断出程序的代码将不会再访问某数据项时,自动清除无主的堆对象。我们因此可以不再操心这项使用其他编程语言时非常容易出错的工作了。

image

值类型和引用类型

数据项的类型定义了存储数据需要的内存大小及组成该类型的数据成员。类型还决定了对象在内存中的存储位置——栈或堆。

类型被分为两种:值类型和引用类型,这两种类型的对象在内存中的存储方式不同。

  • 值类型只需要一段单独的内存,用于存储实际的数据。
  • 引用类型需要两段内存。
    • 第一段存储实际的数据,它总是位于堆中。
    • 第二段是一个引用,指向数据在堆中的存放位置。
image

存储引用类型对象的成员

例如,假设有一个引用类型的实例,名称为MyType,它有两个成员:一个值类型成员和一个引用类型成员。它将如何存储呢?是否是值类型的成员存储在栈里,而引用类型的成员如图3-9所示的那样在栈和堆之间分成两半呢?答案是否定的。

请记住,对于一个引用类型,其实例的数据部分始终存放在堆里。既然两个成员都是对象数据的一部分,那么它们都会被存放在堆里,无论它们是值类型还是引用类型。

image

对于引用类型的任何对象,它所有的数据成员都存放在堆里,无论它们是值类型还是引用类型。

C#类型的分类

image

数组

数组是引用类型,与所有引用类型一样,有数据的引用以及数据对象本身。引用在栈或堆上,而数组对象本身总是在堆上。

image

尽管数组总是引用类型,但是数组的元素可以是值类型也可以是引用类型。

  • 如果存储的元素都是值类型,数组被称作值类型数组。
  • 如果存储在数组中的元素都是引用类型对象,数组被称作引用类型数组。

方法

方法的局部变量和参数是位于栈上的。

class MyClass
{
    public void ListInts(params int[] inVals)
    {
        if ((inVals != null) && (inVals.Length != 0))
            for (int i = 0; i < inVals.Length; i++) //处理数组
            {
                inVals[i] = inVals[i] * 10;
                Console.WriteLine("{0}", inVals[i]); //显示新值
            }
    }
}

class Program
{
    static void Main()
    {
        int first = 5, second = 6, third = 7; //声明3个int 
        MyClass mc = new MyClass();
        mc.ListInts(first, second, third); //调用方法

        Console.WriteLine("{0}, {1}, {2}", first, second, third);
    }
}

输出

50 
60 
70 
5, 6, 7 
image

栈帧

在调用方法的时候,内存从栈的顶部开始分配,保存和方法关联的一些数据项。这块内存叫做方法的栈帧(stack frame)。

  • 栈帧包含的内存保存如下内容

    • 返回地址,也就是在方法退出的时候继续执行的位置。
    • 这些参数分配的内存,也就是方法的值参数,或者还可能是参数数组(如果有的话)。
    • 各种和方法调用相关的其他管理数据项。
  • 在方法调用时,整个栈帧都会压入栈。

  • 在方法退出的时候,整个栈帧都会从栈上弹出。弹出栈帧有的时候也叫做栈展开(unwind)。

class Program
{
    static void MethodA(int par1, int par2)
    {
        Console.WriteLine("Enter MethodA: {0}, {1}", par1, par2);
        MethodB(11, 18); //调用MethodB
        Console.WriteLine("Exit MethodA");
    }

    static void MethodB(int par1, int par2)
    {
        Console.WriteLine("Enter MethodB: {0}, {1}", par1, par2);
        Console.WriteLine("Exit MethodB");
    }

    static void Main()
    {
        Console.WriteLine("Enter Main");
        MethodA(15, 30); //调用MethodA 
        Console.WriteLine("Exit Main");
    }
}

输出

Enter Main 
Enter MethodA: 15, 30 
Enter MethodB: 11, 18 
Exit MethodB 
Exit MethodA 
Exit Main
image

递归

除了调用其他方法,方法也可以调用自身。这叫做递归。

调用方法自身的机制和调用其他方法其实是完全一样的。都是为每一次方法调用把新的栈帧压入栈顶。

class Program 
{ 
    public void Count(int inVal) 
    { 
        if (inVal == 0) 
            return; 
        Count(inVal - 1); //再一次调用方法
        Console.WriteLine("{0}", inVal); 
    } 
 
    static void Main() 
    { 
        Program pr = new Program(); 
        pr.Count(3); 
    }
}
image

相关文章

  • C# 中的栈和堆

    本文是《C# 图解教程》的笔记。 程序运行时,它的数据必须存储在内存中。一个数据项需要多大的内存、存储在什么地方、...

  • C#中的堆和栈理解

    引言:程序运行时,它的数据必须存在内存中,一个数据需要多大内存、存储在什么地方以及如何存储都依赖于该数据的数据类型...

  • c#中的堆与栈

    简介:我们把内存分为堆空间和栈空间线程堆栈:简称栈 Stack 栈空间比较小,但是读取速度快托管堆:...

  • 堆与栈 堆区和栈区的区别

    一、 栈和堆事数据结构中的叫法,栈区和堆区是进程的内存模型中的堆区和栈区 二 内存模型里堆区和栈区和数据结构没有关...

  • OC中的Block

    操作系统中的栈和堆 注:这里所说的堆和栈与数据结构中的堆和栈不是一回事。 栈区(stack):由系统自动分配,一般...

  • js/jquery 学习笔记

    理解JavaScript中的堆和栈 这里先说两个概念:1、堆(heap)2、栈(stack)堆是堆内存的简称。栈是...

  • Java中的堆和栈

    堆和栈都是Java在Ram中存放数据的地方,Java自动管理堆和栈,开发者不能直接地设置堆或栈。 Java的堆是一...

  • 栈和堆以及栈区和堆区的区别

    栈和堆以及栈区和堆区的区别 数据结构中的栈和堆 栈:具有先进后出性质的数据结构 堆:一种经过排序的树形数据结构,节...

  • 【Javascript】探究javascript中的堆/栈/任务

    堆/栈/队列 在javascript中,存在调用栈 (call stack)和内存堆(memory heap) ,...

  • C#中的List、Dictionary、事件、栈和堆、struc

    List 内部是用数组实现的,效率并不高,只是通用性强。如果可以的话,最好在构造List时提前告知它最多会有多少元...

网友评论

      本文标题:C# 中的栈和堆

      本文链接:https://www.haomeiwen.com/subject/vzmanftx.html