标签:
编程语言的发展史就像一份记录,记载着编程语言不断走向抽象化和自动化的过程。
静态分配是最简单的分配策略。程序中所有的变量名都在编译时绑定在某个存储位置上,这些绑定不会在运行时改变。静态分配有 3 个局限:
不过,静态分配的确有 2 个重要的优点:
块结构语言通过在栈上分配内存,克服了静态分配的一些限制。每次过程调用时,一个活动记录(activation record)或是帧被压入系统栈,并在返回时弹出。基于栈的分配方式有 5 个特点:
与栈所遵循的后进先出的规律不同,堆中的数据结构能够以任意次序分配与释放。因而活动记录和动态数据结构可能比创建它们的过程更长寿。堆分配有许多优点:
程序可以直接操作下列 3 种位置中的值:寄存器、程序栈(包括局部变量和临时变量)和全局变量。在这些位置中,有些值保存了指向堆数据的引用,它们构成了根(root)集合。
堆中独立分配的数据,我们可以称之为节点(node)、单元(cell)或对象(object)。从存储机制的角度看,堆中对象构成的图的存活性(liveness)由指针的可到达性(pointer reachability)所定义。堆中对象存活的条件是:某个根保存着它的地址,或是另外一个存活的堆节点保存了指向它的指针。换句话说,堆中存活的节点的集合是根集合在这个关系下传递引用的闭包(transitive referential closure),也就是最小集合 live:
我们注意到,对于堆中存活单元的上述观点,只是对程序实际有可能访问到的单元集合的一个保守估计。它可能包括了一些这样的单元:经由对程序正文的分析或是由一个优化的编译器进行的数据流的分析,我们可以确定它们其实已经死亡。典型的例子包括过程中已经使用完毕的局部变量,帧栈中尚未初始化的位置或是遗留在寄存器中的已经被丢弃的指针(为了避免清除它的开销)。
要确定一个节点的存活性,既可以采用直接的方法,也可以采用间接的方法。直接的方法需要为堆中每一个节点关联一份记录,记录其他堆节点或是根节点到该节点的引用。其中最常见的方法是在这个单元内部保存指向这个单元的指针的数量,也就是它的引用计数法值(reference count)。为分布式系统设计的直接算法,可能为每一个对象保存一个包含有指向该对象引用的远端处理机的列表,以取代简单的引用计数。无论哪一种,当用户程序改变堆中图的连通性时,这些记录必须随之更新。
间接的或者说追踪到的收集器的典型做法,则是在每次用户程序请求更多内存失败时,重新生成存活节点的集合。收集器从根出发,沿着指针链,访问所有可到达的节点。这些节点被认为是存活的,而让所有其他节点所占据的内存变得可以回收利用。如果恢复了足够多的内存,用户程序的请求得到满足时,可以重新开始运行。
标签:
原文地址:http://www.cnblogs.com/thens/p/5617214.html