C# 中的栈和堆

本文是《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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容