收藏 分享(赏)

java与c 的垃圾回收机制.doc

上传人:无敌 文档编号:42299 上传时间:2018-03-05 格式:DOC 页数:6 大小:88.50KB
下载 相关 举报
java与c 的垃圾回收机制.doc_第1页
第1页 / 共6页
java与c 的垃圾回收机制.doc_第2页
第2页 / 共6页
java与c 的垃圾回收机制.doc_第3页
第3页 / 共6页
java与c 的垃圾回收机制.doc_第4页
第4页 / 共6页
java与c 的垃圾回收机制.doc_第5页
第5页 / 共6页
点击查看更多>>
资源描述

1、Java与C#的垃圾回收机制 Java与 C#的垃圾回收机制 收藏 (一)垃圾回收器的基本假定 (1)最近被分配内存空间的对象最有可能需要被释放。在方法被执 行前,通常需要为该方法所使用到的对象分配内存空间,搜索最近被 分配的对象集合有助于花费最少的工作来释放进可能多的空闲内存 空间。 (2)生命期最长的对象需要释放的可能性最小。在通过几轮垃圾回 收后仍然存在的对象不大可能是那种能够在下一轮回收中被释放的 临时对象,搜索这些内存块往往要进行大量的工作,却只能释放很小 一部分的内存空间。 (3)同时分配内存的对象通常也会同时使用。将同时分配内存的对 象存储位置彼此相连有助于提高缓存性能。 (二)

2、几种垃圾回收机制 (1)标记清除收集器 这种收集器首先遍历对象图并标记可到达的对象, 然后扫描堆栈 以寻找未标记对象并释放它们的内存。 这种收集器一般使用单线程工 作并停止其他操作。 (2)标记压缩收集器 有时也叫标记清除压缩收集器, 与标记清除收集器有相同 的标记阶段。在第二阶段,则把标记对象复制到堆栈的新域中以便压 缩堆栈。这种收集器也停止其他操作。 (3)复制收集器 这种收集器将堆栈分为两个域,常称为半空间。每次仅使用一半 的空间,jvm 生成的新对象则放在另一半空间中。gc 运行时,它把可 到达对象复制到另一半空间,从而压缩了堆栈。这种方法适用于短生 存期的对象,持续复制长生存期的对象

3、则导致效率降低。 (4)增量收集器 增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾。这会造成 较小的应用程序中断。 (5)分代收集器 这种收集器把堆栈分为两个或多个域,用以存放不同寿命的对 象。jvm 生成的新对象一般放在其中的某个域中。过一段时间,继续 存在的对象将获得使用期并转入更长寿命的域中。 分代收集器对不同 的域使用不同的算法以优化性能。 (6)并发收集器 并发收集器与应用程序同时运行。这些收集器在某点上(比如压 缩时)一般都不得不停止其他操作以完成特定的任务,但是因为其他 应用程序可进行其他的后台操作, 所以中断其他处理的实际时间大大 降低。 (7)并行收集器 并行收集器使用某

4、种传统的算法并使用多线程并行的执行它们 的工作。在多 cpu机器上使用多线程技术可以显著的提高 java 应用 程序的可扩展性。 (三).NET框架垃圾回收机制 .NET 框架包含一个托管堆,所有的.NET 语言在分配引用类型对 象时都要使用它。像值类型这样的轻量级对象始终分配在栈中,但是 所有的类实例和数组都被生成在一个内存池中, 这个内存池就是托管 堆。 .NET框架中的垃圾回收器被称为分代的垃圾回收器 (Generational Garbage Collector) ,也就是说被分配的对象划分 为3 个类别,或称为“代”。分别为0,1,2。0、1、2 代对应的托 管堆的初始化大小分别是

5、256K,2M 和10M。垃圾回收器在发现改变 大小能够提高性能的话,会改变托管堆的大小。例如当应用程序初始 化了许多小的对象,并且这些对象会被很快回收的话,垃圾回收器就 会将第0代的托管堆变为 128K,并且提高回收的频率。如果情况相 反,垃圾回收器发现在第 0代的托管堆中不能回收很多空间时,就会 增加托管堆的大小。在应用程序初始化的之前,所有等级的托管堆都 是空的。当对象被初始化的时候,他们会按照初始化的先后顺序被放 入第0 代的托管堆中。 最近被分配内存空间的对象被放置于第 0代,因为第 0 代很小,小到足以放进处理器的二级(L2)缓存,所以第 0 代能够为我们提供 对其中对象的快速存取

6、。经过一轮垃圾回收后,仍然保留在第 0代中 的对象被移进第1代中,再经过一轮垃圾内存回收后,仍然保留在第 1 代中的对象则被移进第 2 代中。第2代包含了生存期较长的对象, 这些对象至少经过了两轮回收。 C#程序为一个对象分配内存时, 托管堆几乎可以立即返回新对象 所需的内存, 托管堆之所以能有这样高效的内存分配性能是由于托管 堆较为简单的数据结构。托管堆类似于简单的字节数组,有一个指向 第一个可用内存空间的指针。 在某块被某对象所请求时,上述指针值就会返回给调用函数,而 指针会重新调整至指向下一个可用的内存空间。 分配一个托管内存块 只比递增一个指针的值稍微复杂一点。 这也是托管堆所优化的性

7、能之 一。在一个不需太多垃圾回收的应用程序中,托管堆的表现会优于传 统的堆。 由于这个线性的内存分配方法的存在,在C#应用程序中同时分 配的对象在托管堆上通常会被分配成彼此相邻。 着安排和传统的堆内 存分配完全不同,传统的堆内存分配是基于内存块大小的。例如,两 个同时分配的对象在堆上的位置可能相距很远, 从而降低了缓存的性 能。因此虽然内存分配很快,但在一些比较重要的程序中,第 0代中 的可用内存很有可能会彻底被消耗光。记住,第0 代小到可以装进 L2缓冲区,并且没有被使用的内存不会被自动释放。当第 0 代中没 有可以分配的有效内存时,就会在第0 代中触发一轮垃圾回收,在这 轮垃圾回收中将删除

8、所有不再被引用的对象, 并将当前正在使用中的 对象移至第1 代。针对第0代的垃圾回收是最常见的回收类型,而且 速度很快。在第0代的垃圾内存回收不能有效的请求到充足的内存 时,就启动第1 代的垃圾内存回收。第 2 代的垃圾内存回收要作为最 后一种手段而使用, 当且仅当第1 代和第 0 代的垃圾内存回收不能被 提供足够内存时进行。 如果各代都进行了垃圾回收后仍没有可用的内 存,就会引发一个OutOfMemeryException 异常 。 (四)Java垃圾回收机制 执行Java程序时内存如何放置?Java编程思想一书中提到了六个地方: (1)寄存器(Register) (2)栈(Stack) (

9、3)堆(Heap) :用来置放所有 Java对象 (4)静态存储空间(Static storage) :用来存放“程序执行期间” 一直存在的数据。用 statci 修饰。 (5)常量存储空间(Constant storage) (6)Non-RAM存储空间:我理解为磁盘存储区,即非内存区域。 Sun HotSpot 1.4.1 使用分代收集器,它把堆分为三个主要的域: 新域、旧域以及永久域。Jvm 生成的所有新对象放在新域中。一旦对 象经历了一定数量的垃圾收集循环后,便获得使用期并进入旧域。在 永久域中jvm 则存储 class 和method对象。就配置而言,永久域是 一个独立域并且不认为是

10、堆的一部分。这样看来,采用了 HotSpot 引 擎技术的JVM应该采用了和.NET框架类似的垃圾回收机制-分代 垃圾回收方法。 下面介绍如何控制这些域的大小。可使用-Xms 和-Xmx 控制整个堆的 原始大小或最大值。 下面的命令是把初始大小设置为128M: java Xms128m Xmx256m为控制新域的大小, 可使用-XX:NewRatio 设置新域在 堆中所占的比例。 下面的命令把整个堆设置成 128m,新域比率设置成3,即新域与 旧域比例为1:3,新域为堆的1/4 或32M: java Xms128m Xmx128m XX:NewRatio =3可使用-XX:NewSize和-X

11、X:MaxNewsize 设置新域 的初始值和最大值。 下面的命令把新域的初始值和最大值设置成64m: java Xms256m Xmx256m Xmn64m 永久域默认大小为 4m。运行程序时,jvm 会调整永久域的大小以 满足需要。每次调整时,jvm 会对堆进行一次完全的垃圾收集。 使用-XX:MaxPerSize 标志来增加永久域搭大小。在WebLogic Server 应用程序加载较多类时,经常需要增加永久域的最大值。当 jvm 加载类时,永久域中的对象急剧增加,从而使jvm不断调整永久 域大小。为了避免调整,可使用-XX:PerSize 标志设置初始值。 下面把永久域初始值设置成 3

12、2m,最大值设置成 64m。 java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m 默认状态下,HotSpot 在新域中使用复制收集器。该域一般分为 三个部分。第一部分为 Eden,用于生成新的对象。另两部分称为救 助空间,当Eden 充满时,收集器停止应用程序,把所有可到达对象 复制到当前的from救助空间,一旦当前的from 救助空间充满,收集 器则把可到达对象复制到当前的 to 救助空间。From 和to救助空间 互换角色。维持活动的对象将在救助空间不断复制,直到它们获得使 用期并转入旧域。 使用-XX:

13、SurvivorRatio可控制新域子空间的大小。 同NewRation一样,SurvivorRation 规定某救助域与 Eden 空间 的比值。比如,以下命令把新域设置成 64m,Eden占 32m,每个救助 域各占16m: java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2 如前所述,默认状态下HotSpot对新域使用复制收集器,对旧域 使用标记清除压缩收集器。在新域中使用复制收集器有很多意 义,因为应用程序生成的大部分对象是短寿命的。理想状态下,所有 过渡对象在移出Eden 空间时将被收集。如果能够这样的话,并且移 出Eden 空间

14、的对象是长寿命的,那么理论上可以立即把它们移进旧 域,避免在救助空间反复复制。但是,应用程序不能适合这种理想状 态,因为它们有一小部分中长寿命的对象。最好是保持这些中长寿命 的对象并放在新域中,因为复制小部分的对象总比压缩旧域廉价。为 控制新域中对象的复制,可用-XX:TargetSurvivorRatio 控制救助空 间的比例(该值是设置救助空间的使用比例。如救助空间位 1M,该 值50表示可用500K) 。该值是一个百分比,默认值是 50。当较大的 堆栈使用较低的sruvivorratio时,应增加该值到80 至90,以更好 利用救助空间。用-XX:maxtenuring threshol

15、d可控制上限。 为放置所有的复制全部发生以及希望对象从eden 扩展到旧域,可以把MaxTenuring Threshold设置成0。设置完成后,实际上就不 再使用救助空间了,因此应把SurvivorRatio 设成最大值以最大化 Eden空间,设置如下: java -XX:MaxTenuringThreshold=0 XX:SurvivorRatio 50000 后记:正如Java本纪之Java虚拟机的10年所提到的那样“最 近的五年,就是(JVM)继续优化的五年。继续进行优化的方法有几 条路,一是研究新的采样算法。因为采样关系到不同的优化策略,会 对整体性能有比较大的影响。二是研究深度优化

16、的方法。三是研究垃 圾收集的算法。垃圾收集会带来程序短暂的停顿,这会带来负面的用 户体验。于是,如何提高垃圾收集的效率,减少延迟,出现了五花八 门的算法,比如渐进式收集、火车算法等。”提高语言的执行速度和 效率一直是设计开发者所追求的目标, 因此垃圾回收的算法也会随日 月的递增而发展。我想也没有哪个面试官敢轻易问你谈谈 C#或者 Java的垃圾回收机制(至少我还没碰到过) ,很多问题一旦讨论的深 入,足以写成长篇大著。但刨根问底、追根溯源真的是一件很美的事 情,孔子登东山而小鲁,登泰山而小天下。 参考文献: Java 编程思想第 2 版 Visual C#.NET 技术内幕 Java 本纪之Java虚拟机的10年 深入理解.NET 内存回收机制 深入.NET托管堆(managedheap)

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报