zoukankan      html  css  js  c++  java
  • 基础才是重中之重~理解内存中的栈和堆

    回到目录

    .NET中使用stack(栈)和heap(堆)两种结构在内存中存储数据,今天咱们就来说说这两个结构

    1. Value Types,值类型
            在C#中,值类型继承自System.ValueType的,它们分别是
            Bool,   byte ,  char, decimal, double, enu, float, int, long, sbyte, short, struct, uint, ulong, ushort
    2. Reference Types 引用类型
         
      引用类型包括所有的从System.Object继承下来的类型,它们分别是
             class, interface, delegate, object,string,其中string是一种特殊的引用类型,之后的文章中我会单独说它,.net中的gc(垃圾回收)主要是回收heap中的内存。
    3. 指针:在C#中它已经被遗忘,但不能不说,因为引用类型在内在中事实上是以指针的形式存储在Stack上的,而它的数据内容是在Heap上,也就是上引用类型其实是在stack上做了一个地址的引用。

    Stack是自我维护的,意味着基本上不需要我们手动进行内存管理,它有自己的内存管理体系,对于window来说最高是1M,而.net最大只能用256K没有记错的话,如果超出这个范围就会出现溢出。 而heap则是我们建立object对象所存储的地方,它可以由我们自己用GC去回收也可以由.net自己去回收。

    对于在教科书上的一个例子,我要说一下,就是斐波那切数列问题,一般书上都是用递归写的,这对于程序员的影响事实上是很大的,如果程序员用普通的递归写这个算法,那你的服务没准什么时候就挂了,原因是内存出现stack溢出的现象,具体的原因用“老赵”同志写了段话非常有代表性:它把普通递归改写成了尾递归解决了这个问题。

    int FactorialTailRecursion(int n, int acc)
    {
    if (n == 0) return acc;
    return FactorialTailRecursion(n - 1, acc * n); //变量仍然对程序有影响,所以编译器会一次一次堆累它使用的内存
    }

    改成尾递归之后:

    int FactorialLoopOptimized(int n, int acc)
    {
    while (true)
    {
    if (n == 0) return acc;

    acc *= n;
    n--;
    }
    }

    方法之前所积累下的各种状态对于递归调用结果已经没有任何意义,因此完全可以把本次方法中留在堆栈中的数据完全清除,把空间让给最后的递归调用。这样 的优化便使得递归不会在调用堆栈上产生堆积,意味着即时是“无限”递归也不会让堆栈溢出”。这其实才是尾递归的“正统”优化方式,那么我们先暂时忘记之前 的“循环优化”,从最简单的示例中查看这样的优化是如何进行的。

    在这里,感谢老赵同志对基础的透彻讲解。

    回到目录

  • 相关阅读:
    一些软件设计的原则
    网站的分布式架构
    架构设计--逻辑层 vs 物理层
    社会化海量数据采集爬虫框架搭建
    面向设计原则理解
    职场中架构师面试,你会怎么回答?
    支撑5亿用户、1.5亿活跃用户的Twitter最新架构详解及相关实现
    关键路径法
    团队建设动车模型
    案例:双代号网络图在控制工程造价中的应用
  • 原文地址:https://www.cnblogs.com/lori/p/2346207.html
Copyright © 2011-2022 走看看