Java性能最后一个领域:去除垃圾回收器

来自RedHat的性能和OpenJDK开发者Aleksey Shipil v,提交了一份新的JEP草案,其内容为创建一个无操作垃圾回收器:一种实际上不进行实际内存回收的GC方式。该回收器旨在帮助JVM实现者和研究者,以及少部分无需垃圾回收的超高性能应用程序。如果这项JEP继续推进,新的GC方式将会和现有GC方式一起存在,并且通过显式激活方式使用。

垃圾回收和Java性能向来都是复杂的话题,为了能够更清晰的说明,InfoQ联系了Java Champions成员、性能专家Martijn Verburg和Kirk Pepperdine。同时,我们也联系了无GC Log4j转型领导者Remko Popma,作为如何实现这一GC方式的代表人物之一。Martijn和Remko确认,在他们看来,无操作GC——既Epsilon GC的首要受益者是GC的开发者和性能研究人员。Epsilon GC可以作为度量其他垃圾回收器性能的对照组。一个简单的例子,我们可以将一个应用程序的GC方式设置成无操作GC以减少GC开销(以避免内存分配和其他不可控因素)。如果相同应用程序在相同情况下运行,只是修改了不同GC算法配置,性能上的不同就可以证明该种GC方式在性能上的开销。这将会帮助GC开发者和性能研究人员在更加孤立的方式理解垃圾回收行为。

“我认为这实际上是对精确度量JVM各个部分跨出的一大步。(例如现存JIT的C1/C2编译器,可能会被转移到Graal等)。它将会为JVM增加额外的寿命。”——Martijn Verburg

另一方面,一些对性能严格要求的应用程序也将会从Epsilon GC受益。有非常少见的应用程序和库,例如前文提到的Log4j,已经被设计成不产生垃圾,因此他们无需使用垃圾回收器。对于这种类型应用程序,移除垃圾回收器可以提升性能。然而,如Remko强调的,构建一个可以运行在Epsilon GC的库,“将花费大量的工程努力,以确保应用程序的内存被自己管理,不会耗尽”。但是这样也必须进行风险和性能评估,以确认选择无操作GC的收益和实现无垃圾状态做的努力是否相同。

应用程序如何可以不产生垃圾看上去很难想象,而且这个话题已经复杂到超出本文讨论的范畴,但是如果考虑以下几个方面可能会容易理解:

JVM将内存分成两个部分来管理:堆和栈。这就是为什么当缺少内存时会有两个不同的错误(OutOfMemoryError和StackOverflowError)。栈内存只能被当前线程和当前执行的方法访问,因此,当线程离开当前执行的方法,这块内存会被自动释放,而无需额外垃圾回收器。然而,堆内存可以被整个应用程序在任何时刻访问,这意味着独立的垃圾回收器需要区分内存块什么时候才不被使用,可以被回收。基本数据类型内存总是在栈上分配,因此这对垃圾回收器没有压力。如果代码中基本上都使用基本类型,那么垃圾回收器处理的对象就少了。不产生垃圾不等于不创建对象,如果对象创建满足以下几个条件,仍然可以在创建对象之后不需要垃圾回收器:应用程序或者库在初始化的时候生成有限个数的对象,然后不断复用这些对象。但是这需要依赖开发者非常熟悉应用程序的内存占用。有的时候编译器可以发现一些特定对象不会在方法外使用,这被称为逃逸分析。当确认对象生命周期不会超过方法,其内存可以分配到栈而非堆。因此,这些对象占用的内存会在当前方法结束的时候自动消除。
虽然去除垃圾回收可能实现,Kirk指出这样编写代码会非常不自然,并且会失去Java提供的很多特性。Martijn也同时指出,内存管理恰恰也是Java能够在业界成功的一个主要原因。另外,我们需要牢记,虽然被叫做垃圾回收器,垃圾回收器的任务不仅仅是回收无用的内存,还包括分配新的内存块,Epsilon GC仍然需要实现该功能。这也正是Kirk的论据,至少理论上,使用Epsilon GC和将其他垃圾回收算法配置成实际不进行垃圾回收之后,在性能上没有显著差异。

然而,尽管考虑到所有这些注意事项,Kirk和Martijn证实Epsilon GC还是会对一小部分受众非常有用,但是根据Kirk所说,这些受众将非常少,并怀疑它的实际用处。绝大部分应用程序需要在一些时刻回收内存,因此需要一个有实际功能的垃圾回收器。

“合理的GC停顿时间对于大部分应用程序来说不是问题,因此为什么要为了一个可能存疑的性能优势而放弃Java的所有好处?”——Kirk Pepperdine

Kirk同时提到,新增的每一项新特性都会增加OpenJDK的维护成本,因此OpenJDK开发人员在添加新特性时必须有全局考虑。Oracle一直在减少垃圾回收器的数量,以降低维护成本,因此为一小部分用户添加一个垃圾回收器可能不是一个合理的投资。Aleksey在起草JEP草案的时候,看上去考虑到了这些点,通过JEP草案内容和已经提供的原型来看,初步分析开销可能不大。事实上,Kirk和Martijn同时指出,考虑到Aleksey的经验,应该对他所领导的这个倡议保持乐观。

另一方面,Kirk也强调,虽然OpenJDK是JVM的一个参考实现,但是对垃圾回收器没有强制性要求,这意味着只要完全兼容Java规范,分发者可以有他们自己的垃圾回收算法实现。这可能导致公众意见的分歧:其中一部分人可能认为为特定市场实现的算法可能更适合商业版本的JVM,另一些人可能会认为这对OpenJDK是一个非常有用的补充。

Remko还建议当性能变得至关重要时,应该考虑使用商业版JVM,因为在购买许可证上的开销会比让工程师选择和调优特定的GC算法要小。但是,即使有些人只选择使用OpenJDK,Remko和Martijn都提到当前正在开发中的Shenandoah GC,其目的是针对非常大的堆内存(100GB甚至更大)也只有超低停顿时间。无论如何,专家们的共识是,当应用程序遇到性能问题时,一个经过谨慎选择的GC算法总是优于完全没有GC。

该提案仍然处于初级阶段,在称为正式JEP之前仍需要进行审查和润色。让它称为正式稿之后,将会被加入到JVM版本中。虽然目前我们只能推测最终会添加到什么版本JVM中,Martijn认为有理由期待Epsilon GC将会加入到Java 10或者11。如果要说有什么好处的话,Epsilon GC至少能够帮助理解GC的接口,有助于成就一个更加模块化的JVM。

本文转自d1net(转载)

时间: 2024-12-22 12:13:22

Java性能最后一个领域:去除垃圾回收器的相关文章

java 垃圾回收-Java怎么查看目前所用的垃圾回收器是哪一个?

问题描述 Java怎么查看目前所用的垃圾回收器是哪一个? 如题............................................................................... 解决方案 监控工具在bin/jvisualvm.exe 解决方案二: VisualVM 是Netbeans的profile子项目,已在JDK6.0 update 7 中自带(java启动时不需要特定参数,监控工具在bin/jvisualvm.exe),能够监控线程,内存情况,查

探秘Java 7新增垃圾回收器G1特性

G1垃圾回收器(简称G1 GC)是JDK 7中Java HotSpot VM新引入的垃圾回收器,Java SE 6 Update 14中已经包含了一个G1的体验版本(据51CTO之前的报导,在Java SE 6 u14于6月初登场时,原本Sun的声明是:G1垃圾回收器需要收费方能使用.然而之后不久,Sun表示这是一个误会,修改了原本的发布声明,并表示现在以及将来对G1的使用都是完全免费的),G1是设计用于替代HotSpot低延迟的并行标记/清除垃圾回收器(也叫做CMS)的. Java 7 G1属

C++内存管理变革(2):最袖珍的垃圾回收器

概述 C/C++最被人诟病的,可能是没有一个内存垃圾回收器(确切是说没有一个标准的垃圾回收器).本文讨论的内容要点是,在C/C++中实现一个最袖珍的.功能受限的垃圾回收器.这个垃圾回收器区别于其他垃圾回收器的主要特征是: 1. 袖珍但具实用性.整个垃圾回收器代码行数100行左右(不含空白行),相当小巧.相对而言,它的功能也受到一定的限制.但是它在很多关键的场合恰恰非常有用.该垃圾回收器以实用作为首要目标,已经成为我和身边一些同事编程的重要工具. 2. 高性能.区别于其他垃圾回收器的是这个袖珍的垃

Java垃圾回收器的方法和原理总结_java

什么是Java垃圾回收器 Java垃圾回收器是Java虚拟机(JVM)的三个重要模块(另外两个是解释器和多线程机制)之一,为应用程序提供内存的自动分配(Memory Allocation).自动回收(Garbage Collect)功能,这两个操作都发生在Java堆上(一段内存快).某一个时点,一个对象如果有一个以上的引用(Rreference)指向它,那么该对象就为活着的(Live),否则死亡(Dead),视为垃圾,可被垃圾回收器回收再利用.垃圾回收操作需要消耗CPU.线程.时间等资源,所以容

浅谈关于Java的GC垃圾回收器的一些基本概念_java

一.基本回收算法 1. 引用计数(Reference Counting) 比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回收时,只用收集计数为0的对象.此算法最致命的是无法处理循环引用的问题. 2. 标记-清除(Mark-Sweep) 此算法执行分两阶段.第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除.此算法需要暂停整个应用,同时,会产生内存碎片. 3. 复制(Copying) 此算法把内存空间划为两个相等的区域

Java垃圾回收器工作原理

垃圾回收器是如何工作的?我现在就简单的介绍一下 首先要明确几点: Java是在堆上为对象分配空间的 垃圾回收器只跟内存有关,什么IO啊,网络连接啊,管它P事 当可用内存数量较低时,Sun版本的垃圾回收器才会被激活 在垃圾回收器回收垃圾之前,我们先来了解一下Java分配对象的方式,Java的堆更像一个传送带,每分配一个新对象,它就往前移动一格.这意味着对象存储空间的分配速度相当快.Java的"堆指针"只是简单地移动到尚未分配的领域.也就是说,分配空间的时候,"堆指针"

第5章(2) Java的垃圾回收器

终结处理 Java有垃圾回收器回收无用对象占据的内存资源.但垃圾回收器只知道释放经由new分配的内存,如果用其他的方法获得了一块"特殊"的内存区域,就需要我们自己完成清理工作.Java提供了finalize()方法来解决这一问题. finalize()方法: 工作原理:一但垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存. 其作用,换句话说就是:在你不再需要某个对象之前,如果必须执行某些动作,那么你

Java中垃圾回收器GC对吞吐量的影响测试_java

在看内存管理术语表的时候偶然发现了"Pig in the Python(注:有点像中文里的贪心不足蛇吞象)"的定义,于是便有了这篇文章.表面上看,这个术语说的是GC不停地将大对象从一个分代提升到另一个分代的情景.这么做就好比巨蟒整个吞食掉它的猎物,以至于它在消化的时候都没办法移动了. 在接下来的这24个小时里我的头脑中充斥着这个令人窒息的巨蟒的画面,挥之不去.正如精神病医生所说的,消除恐惧最好的方法就是说出来.于是便有了这篇文章.不过接下的故事我们要讲的不是蟒蛇,而是GC的调优.我对天

浅析Java中的GC垃圾回收器的意义及与GC的交互_java

对象是使用new创建的,但是并没有与之相对应的delete操作来回收对象占用的内存.当我们完成对某个对象的使用时,只需停止对该对象的引用:将我们的引用改变为指向其他对象或指向null;或者从方法中返回,使得该方法的局部变量不复存在,从而使得对这些局部变量的引用变为不指向任何对象.不再被引用的对象被称为垃圾(garbage),查找并回收这些对象的过程叫做垃圾回收(garbage collection) o Java虚拟机利用垃圾回收来保证被引用的对象将会在内存中保留,同时会释放在执行代码中通过任何