java虚拟机垃圾回收被误解的7件事

对Java垃圾回收最大的误解是什么?它实际又是什么样的呢?

当 我还是小孩的时候,父母常说如果你不好好学习,就只能去扫大街了。但他们不知道的是,清理垃圾实际上是很棒的一件事。可能这也是即使在Java的世界中, 同样有很多开发者对GC算法产生误解的原因——包括它们怎样工作、GC是如何影响程序运行和你能对它做些什么。因此我们找到了Java性能调优专家Haim
Yadid
,并把名为Java
performance tuning guide
的文章发表在Takipi的博客上。

最新博文:关于垃圾回收被误解的7件事

http://t.co/3QJLJuKCRqpic.twitter.com/aqQEF0zTkK

— Takipi (@takipid) April 6, 2015

带着对性能调优指南浓厚的兴趣,我们决定在这篇后续的博文中收集一些关于垃圾回收的流行观点,并且指出为什么它们完全是错误的。

来看看前7名:

1. 只有一个垃圾回收器

不,并且4也是错误的答案。HotSpot JVM一共有4个垃圾回收器:Serial,
Parallel / Throughput. CMS, and the new kid on the block G1
。别急,另外还有一些非标准的垃圾回收器和更大胆的实现,比如Shenandoah
者其他JVM使用的回收器(C4——Azul开发的无停顿回收器)。HotSpot默认使用Parallel / Throughput回收器,但它常常不是你运行程序的最佳选择。比如CMS和G1会使GC停顿(GC pause)发生的频率降低,但是对于每次停顿所花费的时间,很可能比Parallel回收器更长。另一方面来说,在使用相同大小堆内存的情况下,Parallel回收器能带来更高的吞吐量。

结论:根据你的需求(可接受的GC停顿频率和持续时间)选择合适的垃圾回收器。

2. 并行(Parallel) = 并发(Concurrent)

一个GC周期(Garbage Collection cycle)可以以STW(Stop-The-World)的形式出现,这会发生一次GC停顿,也可以并发地执行从而无需暂停应用程序。更进一步来 讲,GC算法本身可以是串行的(单线程),也可以是并行的(多线程)。因此当我们提到并发的GC时,并不代表它是并行完成的,相反当提到串行GC时,也并 不意味着就一定会出现GC停顿。在GC的世界中,并发和并行是两个完全不同的概念。并发针对的是GC周期,而并行针对GC算法自身。

结论:垃圾回收的过程实际上有两步,启动GC周期和GC自身运行,这是不同的两件事。

3. G1能解决所有问题

经过一系列修正和改 进,Java 7中引入了G1回收器,它是JVM垃圾回收器中最新的组件。G1最大的优势就是解决了CMS中常见的内存碎片问题:GC周期会从老年代(Old Generation)中释放内存块,结果内存变得像瑞士奶酪那样千疮百孔,直到JVM对其无从下手了,才不得不停下来处理这些碎片。但是故事没这么简 单,某些情况下其他回收器可能比G1有更好的表现,这完全取决于你的需求。

结论:没有一个奇迹般的回收器能解决所有GC问题,你应该通过具体实验来选择合适的回收器。

4. 平均事务时间是最需要被关注的指标

如 果你仅仅监控服务器的平均事务时间,那么很可能错过一些异常值。这些异常的情况可能对用户来说是毁灭性的,而人们没有意识到它的重要性。比如一个事务在正常情况下耗时100ms,但受到GC停顿的影响,花了1分钟才完成。除了用户没人会注意到这个问题,因为你只观察了平均事务时间。试想有1%或者更多的用 户经历了这个场景,如果只关注平均值,它就太容易被忽略了。想了解更多和延迟相关的问题和怎样正确处理,可以在这里阅读Gil
Tene
的博客。

结论:留心那些异常值,你可以知道系统最后那1%的状况。(可不是这个1%

5. 降低新对象的分配率可以改善GC的运行状况

我们可以 粗略地把系统中的对象分为三种:长命(long-lived)对象,对它们我们一般做不了什么;中等寿命(mid-lived)对象,最大的问题可能出现在这;短命(short-lived)对象,它们的释放和回收通常都很快,在下个GC周期来临时就会消失。专注于中等寿命对象的分配率可以带来有益的结 果,这对短命和长命的对象却不是那么有效。另外,控制中等寿命对象往往是一项困难的工作。

结论:给服务器带来压力的并不单纯是对象的分配率,在运行过程中这些对象的种类才是一切麻烦的根源。

6. 调优可以解决所有事

如果你的程序需要保存大量被频繁修改的状态,对JVM堆内存进行调优就无法带来很好的收益。较长的GC停顿是不可避免的。一个解决办 法是对架构进行改善,保证一个对响应时间有决定性影响或者造成瓶颈的过程中,不包含大量状态。大量状态和响应能力是难以良好共存的,因此将它们分开处理才 是上上之选。

结论:不是所有的问题都可以通过调整JVM参数解决,有时你只需要回顾自己的绘图板。(译注:重新审视程序的设计)

7. GC日志会导致巨大的系统开销

简单来说,这是错的,尤 其在默认的日志配置下。日志数据是极为有价值的,Java 7中还引入了钩子来控制它们的大小,保证硬盘空间不被用尽。如果不收集GC日志,那么你会失去这几乎是唯一的,知晓JVM垃圾回收器在生产环境中工作状态 的方法。一般可接受的GC开销以5%作为上限,如果你能知道系统为GC停顿付出的代价,也能对最小化这个代价采取行动,这种程度的开销是不值一提的。

结论:在能力范围内,尽可能多地获取系统在生产环境中的运行数据,你会发现那是一个全新的世界。

总结

希望上面的结论能帮助你们更好地把握Java垃圾回收器的工作。在你们的程序中出现过类似问题吗?你们周围还有没有其他对GC常见的误解?请在下面的评论区留言。

原文链接: javacodegeeks 翻译: ImportNew.com
生武

译文链接: http://www.importnew.com/15796.html

时间: 2024-08-24 19:42:09

java虚拟机垃圾回收被误解的7件事的相关文章

关于垃圾回收被误解的7件事

转自:http://www.importnew.com/15796.html 对Java垃圾回收最大的误解是什么?它实际又是什么样的呢? 当我还是小孩的时候,父母常说如果你不好好学习,就只能去扫大街了.但他们不知道的是,清理垃圾实际上是很棒的一件事.可能这也是即使在Java的世界中, 同样有很多开发者对GC算法产生误解的原因——包括它们怎样工作.GC是如何影响程序运行和你能对它做些什么.因此我们找到了Java性能调优专家Haim Yadid,并把名为Java performance tuning

JAVA虚拟机垃圾回收算法原理

除了释放不再被引用的对象外,垃圾收集器还要处理堆碎块.新的对象分配了空间,不再被引用的对象被释放,所以堆内存的空闲位置介于活动的对象之间.请求分配新对象时可能不得不增大堆空间的大小,虽然可以使用的总空闲空间是足够的.这是因为,堆中没有连续的空闲空间放得下新的对象. 垃圾收集器算法 任何垃圾回收算法都必须做两件事,首先,它必须检测出垃圾对象.其次,它必须回收垃圾对象所使用的堆空间并还给程序.从根对象开始,任何可以被触及的对象都被认为是“活动的”对象(如果正在运行的程序可以访问到根对象和某个对象之间

Java虚拟机垃圾回收机制

在Java虚拟机中,对象和数组的内存都是在堆中分配的,垃圾收集器主要回收的内存就是再堆内存中.如果在Java程序运行过程中,动态创建的对象或者数组没有及时得到回收,持续积累,最终堆内存就会被占满,导致OOM. JVM提供了一种垃圾回收机制,简称GC机制.通过GC机制,能够在运行过程中将堆中的垃圾对象不断回收,从而保证程序的正常运行. 垃圾对象的判定 我们都知道,所谓“垃圾”对象,就是指我们在程序的运行过程中不再有用的对象,即不再存活的对象.那么怎么来判断堆中的对象是“垃圾”.不再存活的对象呢?

Java虚拟机--垃圾回收机制

Java与C++相比,具有动态分配内存和垃圾回收机制的技术优势,使得我们不用把精力集中在内存的管理上,那我们为什么还要去了解GC和内存分配呢?原因很简单:当需要排查各种内存溢出.内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些"自动化"的技术实施必要的监控和调节. 1.为什么进行垃圾回收  随着程序的运行,系统内存中存在的对象实例.各种变量越来越多,如果不进行垃圾回收,会影响到程序的性能,当占用内存过多时,还会产生OOM等系统异常. 2.哪些内存需要回收 关于

老生常谈Java虚拟机垃圾回收机制(必看篇)

二.垃圾收集 垃圾收集主要是针对堆和方法区进行. 程序计数器.虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收. 判断一个对象是否可被回收 1. 引用计数算法 给对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1.引用计数为 0 的对象可被回收. 两个对象出现循环引用的情况下,此时引用计数器永远不为 0,导致无法对它们进行回收. 正因为循环引用的存在,因此 Java 虚拟机不使用引用计数

29、Java虚拟机垃圾回收调优

一.背景 如果在持久化RDD的时候,持久化了大量的数据,那么Java虚拟机的垃圾回收就可能成为一个性能瓶颈.因为Java虚拟机会定期进行垃圾回收,此时就会追踪所有的java对象, 并且在垃圾回收时,找到那些已经不在使用的对象,然后清理旧的对象,来给新的对象腾出内存空间. 垃圾回收的性能开销,是跟内存中的对象的数量,成正比的.所以,对于垃圾回收的性能问题,首先要做的就是,使用更高效的数据结构,比如array和string:其次就是在持久化rdd时, 使用序列化的持久化级别,而且用Kryo序列化类库

Java面试题之Java虚拟机垃圾回收

JVM的垃圾回收机制,在内存充足的情况下,除非你显式的调用System.gc(),否则不会进行垃圾回收:在内存充足的情况下垃圾回收会自动运行. 一.引用计数算法 1.定义:引用计数算法会给对象添加一个引用计数器,每当有一个地方引用他的时候,计数器就加1:当引用失效的时候计数器值就减1.当计数器为0的时候,对象就可以被收回. 2.缺点:存在循环引用的情况,导致两个循环引用对象的内存得不到释放.目前没有一个JVM垃圾回收实现是使用这个算法的. 3.现状:主流的Java虚拟机没有使用引用计数算法来管理

Java虚拟机垃圾回收算法

1.标记清除算法:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象.缺点是效率问题和产生大量不连续的内存碎片,导致程序后期需要分配大对象时无法找到足够的连续内存而不得不提前出发另一次垃圾收集动作. 2.复制算法:将可用内存划分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉. 3.标记整理算法:让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存. 当前商业虚拟机的垃圾收集都采用分代

Java虚拟机垃圾回收过程

JVM堆中几乎放着Java世界中所有的对象实例,垃圾收集器在对堆内存进行回收前,第一件事情就是要确定这些对象有哪些还存活着,哪些已经死去(即不可能再被任何途径使用的对象). 在主流的商业程序语言中,Java和c#等都是使用根搜索算法(GC Roots Tracing)判定对象是否存活的.这个算法的基本思路就是通过一系列的名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(从GC Roots到这个对