对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常见的误解?请在下面的评论区留言。
- 浏览: 273557 次
- 性别:
- 来自: 杭州
最新评论
-
jnjeC:
第一步:打开日志文件 less sigma.log第二步 ...
linux less从后向前查看日志信息 -
jnjeC:
mac 里面直接按b或f就可以,好像按ctrl没反应
linux less从后向前查看日志信息 -
wiselyman:
写的太好了
从100PV到1亿级PV网站架构演变 -
cfyme:
fu222cs98 写道曹教练最后拿了什么大奖了没啥大奖啊
2015桐庐年会--奔跑吧,骚年 -
fu222cs98:
曹教练最后拿了什么大奖了
2015桐庐年会--奔跑吧,骚年
相关推荐
对Java垃圾回收大的误解是什么?它实际又是什么样的呢? 当我还是小孩的时候,... 带着对性能调优指南浓厚的兴趣,我们决定在这篇后续的博文中收集一些关于垃圾回收的流行观点,并且指出为什么它们完全是错误的。
垃圾回收(Garbage Collection, GC)是指在程序运行过程中自动检测并释放那些不再被使用的对象所占用的内存空间的过程。这一过程通常是由语言的运行环境(如Java虚拟机)自动完成的,而不需要程序员手动干预。 **2....
3. 使用弱引用:弱引用不会阻止对象被垃圾回收,可以在需要时检查对象是否还存活。 4. 调整垃圾回收参数:每个语言都有相应的参数调整GC的行为,如新生代和老年代的比例,以适应不同场景的需求。 通过理解并熟练...
垃圾回收可以在不同的条件下被触发: 1. **系统调用**:开发者可以通过调用`System.gc()`显式请求垃圾回收,但这并不是推荐的做法,因为JVM可能会忽略此请求。 2. **内存不足**:当JVM检测到堆内存不足时,会自动...
7. **性能优化**:垃圾回收会对程序性能产生影响,因此需要合理设置JVM参数,如新生代大小、老年代大小、 survivor比例等,以及选择合适的垃圾收集器。 8. ** finalize() 方法**:Java允许定义一个finalize()方法,...
- **使用限制**:`finalize()` 方法只能被调用一次,且在垃圾回收器准备回收一个对象时才会调用。此外,`finalize()` 方法并不总是被调用,因此不应该依赖于它来进行必要的资源清理。 - **最佳实践**:尽管`finalize...
7. **测试与调试**:实现垃圾回收器后,必须进行全面的测试以确保其正确性和健壮性。这包括边界条件测试、内存泄漏检测和并发安全性的验证。 总的来说,使用C++实现垃圾回收器是一个挑战性的任务,需要深入理解内存...
- 引用计数法则是通过跟踪对象引用计数来回收内存,每个对象有一个引用计数器,当计数器为零时,对象即被认为是可以回收的垃圾。 - 复制算法通过将内存分为两部分,将活跃对象复制到另一部分,从而回收剩余部分的...
在这个模型中,回收的垃圾被视为"Flowitem",由Source产生,进入Queue暂存,再通过Separator进行分类。分类后的垃圾通过Conveyor和FlowNode进行传输,最后被储存在Reservoir中。在这个过程中,Crane和Transporter...
标签"**C++ 垃圾回收机制**"进一步确认了讨论的主题,我们将会看到关于C++中实现自动内存管理的实践和理论。 在压缩包的文件列表中,有以下三个文件: 1. **C++内存管理变革(2):最袖珍的垃圾回收器.mht** - 这个...
Python垃圾回收机制是编程语言中一个重要的组成部分,它主要用于自动管理程序运行时的内存资源,确保内存的有效利用和及时释放。在Python中,垃圾回收机制是实现内存管理的关键工具,帮助程序员避免了手动管理内存...
Java和C#是两种流行的面向对象的编程语言,它们都具备自动内存管理机制,其中垃圾回收(Garbage Collection, GC)是一项核心功能。垃圾回收旨在自动检测并释放不再使用的内存,防止内存泄漏,确保程序的稳定运行。...
Java垃圾回收器是Java虚拟机(JVM)的关键组成部分,它自动管理程序的内存,确保对象的生命周期得到妥善处理,从而避免内存泄漏。本章主要介绍了垃圾回收算法和JVM中实现的不同类型的垃圾回收器。 首先,垃圾回收的...
不可达的对象被视为垃圾,可以被回收。这种方法能有效处理循环引用,但实现起来更为复杂。 一个简单的C++垃圾回收器可能包含以下组件: 1. **标记阶段**:从根对象开始遍历整个对象图,标记所有可达的对象。 2. **...
2. **垃圾回收原理**:垃圾回收器通过跟踪和分析程序中的对象引用关系,找出不再被引用的对象,然后释放它们占用的内存。常见的垃圾收集算法有标记-清除(Mark-Sweep)、复制(Copying)、标记-整理(Mark-Compact)...
.NET 垃圾回收机制也支持终止化(Finalization)概念,它可以在对象被回收时执行一些清除工作,例如释放非受管资源。然而,终止化操作可能会带来额外的开销,并且不推荐在所有情况下使用。 在实际开发中,垃圾回收...
- 使用`finalize()`方法可以让对象在被垃圾回收前有机会执行清理操作,但这个方法的使用应谨慎,因为它可能会干扰垃圾回收过程。 5. **个人笔记** - 调优垃圾回收器涉及多个参数,例如新生代和老年代的比例(`-XX...