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--;
    }
    }

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

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

  • 相关阅读:
    百度之星资格赛1001——找规律——大搬家
    HDU1025——LIS——Constructing Roads In JGShining's Kingdom
    DP(递归打印路径) UVA 662 Fast Food
    递推DP UVA 607 Scheduling Lectures
    递推DP UVA 590 Always on the run
    递推DP UVA 473 Raucous Rockers
    博弈 HDOJ 4371 Alice and Bob
    DFS(深度) hihoCoder挑战赛14 B 赛车
    Codeforces Round #318 [RussianCodeCup Thanks-Round] (Div. 2)
    DP(DAG) UVA 437 The Tower of Babylon
  • 原文地址:https://www.cnblogs.com/ywsoftware/p/3068446.html
Copyright © 2011-2022 走看看