GC 简介

内存分配的历史

编程语言的发展史就像一份记录,记载着编程语言不断走向抽象化和自动化的过程。

静态分配

静态分配是最简单的分配策略。程序中所有的变量名都在编译时绑定在某个存储位置上,这些绑定不会在运行时改变。静态分配有 3 个局限:

  • 每个数据结构的大小必须在编译时可知。
  • 过程是不能递归的,因为对于过程中的每个活动,局部变量在内存中共享相同的位置。
  • 无法动态的创建数据结构。

不过,静态分配的确有 2 个重要的优点:

  • 采用这一策略的编程语言的运行效率高,因为不需要在程序执行时创建或销毁栈帧(stack frame)等数据结构。由于编译器知道所有数据的位置,它可以直接访问而不是简介访问存储位置。
  • 静态分配还提供了一个安全保证:程序不可能因为耗尽内存而运行失败,因为它的内存需求可以预知。

栈分配

块结构语言通过在栈上分配内存,克服了静态分配的一些限制。每次过程调用时,一个活动记录(activation record)或是帧被压入系统栈,并在返回时弹出。基于栈的分配方式有 5 个特点:

  • 同一过程的不同活动中,局部变量不再共享相同的地址。递归调用称为可能,从而大大增强了语言的表达能力。
  • 像数组这样的局部数据结构,其大小可能取决于传递过程的参数。
  • 栈分配的局部变量的值,无法从一个活动保持到下一个活动。
  • 被调用者的活动记录不可能比它的调用者寿命更长。
  • 只有大小能在编译时确定的对象,才能作为过程的结果返回。

堆分配

与栈所遵循的后进先出的规律不同,堆中的数据结构能够以任意次序分配与释放。因而活动记录和动态数据结构可能比创建它们的过程更长寿。堆分配有许多优点:

  • 设计就是通过创建抽象为客观世界的问题建模,而这些抽象中,许多天生具有层次结构,最常见的例子就是链表和树。堆分配使得这类抽象的具体表示是可以递归的。
  • 数据结构的大小不再固定,而是可以动态变化,有可能会发生数组索引越界的问题。
  • 动态大小的对象可以作为过程的结果返回。
  • 许多现代编程语言允许把一个过程作为另一个过程的结果返回。如果禁止嵌套的过程,栈分配的语言也可以做到这一点:它们使用被返回的过程的静态地址。

状态、存活性和指针可到达性

程序可以直接操作下列 3 种位置中的值:寄存器、程序栈(包括局部变量和临时变量)和全局变量。在这些位置中,有些值保存了指向堆数据的引用,它们构成了根(root)集合。

堆中独立分配的数据,我们可以称之为节点(node)、单元(cell)或对象(object)。从存储机制的角度看,堆中对象构成的图的存活性(liveness)由指针的可到达性(pointer reachability)所定义。堆中对象存活的条件是:某个根保存着它的地址,或是另外一个存活的堆节点保存了指向它的指针。换句话说,堆中存活的节点的集合是根集合在这个关系下传递引用的闭包(transitive referential closure),也就是最小集合 live:

live={N∈Nodes∣(∃r∈Roots.r→N)⋁(∃M∈live.M→N)}" role="presentation" style="position: relative;">live={N∈Nodes∣(?r∈Roots.r→N)?(?M∈live.M→N)}live={N∈Nodes∣(?r∈Roots.r→N)?(?M∈live.M→N)}

我们注意到,对于堆中存活单元的上述观点,只是对程序实际有可能访问到的单元集合的一个保守估计。它可能包括了一些这样的单元:经由对程序正文的分析或是由一个优化的编译器进行的数据流的分析,我们可以确定它们其实已经死亡。典型的例子包括过程中已经使用完毕的局部变量,帧栈中尚未初始化的位置或是遗留在寄存器中的已经被丢弃的指针(为了避免清除它的开销)。

要确定一个节点的存活性,既可以采用直接的方法,也可以采用间接的方法。直接的方法需要为堆中每一个节点关联一份记录,记录其他堆节点或是根节点到该节点的引用。其中最常见的方法是在这个单元内部保存指向这个单元的指针的数量,也就是它的引用计数法值(reference count)。为分布式系统设计的直接算法,可能为每一个对象保存一个包含有指向该对象引用的远端处理机的列表,以取代简单的引用计数。无论哪一种,当用户程序改变堆中图的连通性时,这些记录必须随之更新。

间接的或者说追踪到的收集器的典型做法,则是在每次用户程序请求更多内存失败时,重新生成存活节点的集合。收集器从根出发,沿着指针链,访问所有可到达的节点。这些节点被认为是存活的,而让所有其他节点所占据的内存变得可以回收利用。如果恢复了足够多的内存,用户程序的请求得到满足时,可以重新开始运行。

来自为知笔记(Wiz)

时间: 2024-12-28 17:01:27

GC 简介的相关文章

Java垃圾收集器(GC)简介与最佳组合探究

Java经过近20年的演变,已经发展出一套复杂.健壮和高性能的垃圾收集器.在不同的应用场合下使用不同的GC组合能让程序性能得到可观提高.我想这也是Java这么多年来一直处于不败之地的原因之一. 以下讨论只限于Server模式下的HotSpot JVM. GC的类型 Sun/Oracle的HotSpot JVM为我们提供了多种不同的GC,一种GC只专门负责新生代或老年代的内存回收工作,所以实际使用的时候需要我们为新生代和老年代指定不同的GC.但G1例外,因为G1可以通吃整个堆内存. Serial

JVM的GC简介和实例

本文是一次内部分享中总结了jvm gc的分类和一些实例, 内容是introduction级别的,供初学人士参考.成文仓促,难免有些错误,如果有大牛发现,请留言,我一定及时更正,谢谢!JVM内存布局主要包含下面几个部分: Java Virtual Machine Stack: 也就是我们常见的局部变量栈,线程私有,保存线程执行的局部变量表.操作栈.动态连接等. Java Heap:我们最常打交道的内存区域,几乎所有对象的实例都在这个区域分配.所谓的GC基本上也就是跟这个区域打交道. Method

GC简介

最近观察到有一个service做full GC 比较频繁,决定对它进行调优,先整理一下GC的知识. GC分类 GC分为两类:minor GC 和 full GC minor GC:对新生代进行的GC操作.通常采用复制算法,将Eden Space 以及survivor Space 0的不可回收对象复制到survivor Space 1. 触发条件:当Eden Space空间不足时. full GC:对老年代进行的GC操作.通常采用标记-清除算法,即将不可回收对象做上标记,回收其它未被标记对象,这样

jvm-垃圾回收gc简介+jvm内存模型简介

gc是jvm自动执行的,自动清除jvm内存垃圾,无须人为干涉,虽然方便了程序员的开发,但同时增加了开发人员对内存的不可控性. 1.jvm是在计算机系统上又虚拟出来的一个伪计算机系统,它存在于计算机内存中并运行在操作系统之上, jvm在执行字节码时,把字节码解释成具体平台上的机器指令执行,那我们就来看看这个JVM伪计算机系统是怎么设计的,如下是jvm的体系图,运行数据区是jvm的内存模型: 程序计数器:一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器.字节码解释器工作时就是

SSD内部GC简介

SSD内部GC相关特性 P4500是一款广泛使用的NVME SSD是DC P4500,下面的GC介绍和分析就基于P4500进行.其他款可以参考相关手册. P4500读.写.擦除.回收的粒度 P4500内部写是按照物理page 对齐,而擦除是按照物理block对齐,最终GC操作的trim是通过NVME 协议中定义的 deallocate命令(deallocate命令,顾名思义,就是用来告诉SSD控制器哪些page/block里的数据不需要了,可以被SSD 控制器后续擦除.)为此需要对这些参数有一定

【原创】GC/垃圾回收简介

GC简介 1 GC机制 1.1 对象 从计算机的角度,装有数据的内存空间 1.2 作用 将内存垃圾的释放自动化 1.3 本质 将已经引用不到的对象视为死亡,将死亡的对象找出来并且作为垃圾进行回收 2 GC算法 2.1 跟踪回收 2.1.1 原理 从根开始扫描判断对象的生死 2.1.2 标记清除 (1)过程 第一次扫描:以变量或运行栈作为根,从根开始将可能被引用的对象进行标记,将没被标记的对象进行垃圾回收 第二次扫描:将全部对象进行扫描,对没有被标记的对象进行垃圾回收,扫描的同时还需要将存活的对象

JVM——垃圾回收(GC)

GC简介 java语言运行在java虚拟机(jvm)上,为了解决有限的空间和性能的保证这个矛盾体,jvm所具备的GC能力,可以有效的清除不用的对象,使空间的利用更加合理.下面介绍该机制的原理. 判断对象已废弃 引用计数法 给每一个对象都配备一个计数器,对于该对象,若增加一个指向它的引用,则计数器加1:每失效一个引用,则计数器减一. 但是,如果两个对象互相引用,但都对于外部都已失去用途,则这样的两个对象是无法被计数为0的,因为他们的计数器永远都只为1. 可达性分析法 为了解决引用计数法的缺陷,我们

Java GC 小结

很早就想对Java的GC做点小总结,一直没有时间,最近看了下java paper上的java gc文章,觉得不错,读了读,顺便做下总结. java paper的GC文章地址,里面有很多java技术文章,写的都不错. 1.Java GC 简介 JVM的垃圾回收机制使开发者不必过多考虑内存的申请与释放,这样降低了软件开发的成本和语言的学习成本. 不同的JVM对GC的实现是不同的,目前Oracle维护着两种JVM,JRockit JVM,HotSpot JVM. 本文讨论的JVM是居于HotSpot的

JVM参数调优:Eclipse启动实践

本文主要参考自<深入理解 Java 虚拟机>.这本书是国人写的难得的不是照搬代码注释的且不是废话连篇的技术书,内容涵盖了 Java 从源码到字节码到执行的整个过程,包括了 JVM(Java Virtual Machine)的架构,垃圾收集的介绍等.这里摘录出关于配置 JVM 基本参数来调优 Eclipse 启动的过程,比较初级,供初学者参考. 基础知识 针对 JVM 的参数调优主要集中在数据区大小的控制和垃圾回收策略的选择.关于 JVM 运行机制等更多内容可参考其他博文 JVM 的运行时数据区