java虚拟机优化小结
程序员文章站
2022-03-16 13:10:15
...
Java HotSpot虚拟机供了多种垃圾回收器,每一种垃圾回收器都是为了满足不同的需求和环境。通常情况下,Java虚拟机会根据当前运行的应用程序选择一个合适的垃圾回收器。但当我们有一个需要加载很多类,尤其是数据量特别庞大的应用程序时,如何正确选择一个垃圾回收器是至关重要的。
J2SE1.4之前,Java虚拟机不支持并行垃圾回收,所以垃圾回收对一个基于多处理器系统的影响很大。下图是一个扩展性很好的系统模型,但是垃圾回收的效率不尽人意。红线是一个只在垃圾回收上使用1%时间的应用程序,当它运行在32个处理器上的系统上是,20%的生产力被浪费掉了。
Ergonomics是在j2se1.5中加入的一个新功能,它可以为一个几乎或者没有通过命令行参数优化的系统提供一个较好的性能表现。它主要通过选择如下项目来实现优化。
当虚拟机启动时,这些选项是以所运行的应用程序的特征来被Ergonomics选择的。通常会已运行当前应用程序行的机器类型作为参考(大的应用程序运行在性能好的机器上)。添加这些选项是最简单的优化虚拟机的方式。
JavaSE平台的一个强项就是避免用户过多的去考虑内存如何分配,然而一但垃圾回收遇到瓶颈,我们对垃圾回收的实现机制有所了解还是很有必要的。垃圾回收器对应用程序使用对象的方式作出一些假设,这些假设反映在那些可调优的参数上。通过调整这些参数,系统的性能能够得到提升,与此同时系统的抽象性不会受到影响。
当一个对象没有任何引用指向它时,它会被当作'垃圾'。最简单直接的垃圾回收算法是遍历所有能够被指向到的对象,所有未被指向到的对象,就当作'垃圾'了。这个算法实现的时间和当前存活对象的个数成正比,因此这种算法被禁止使用在会有很多存活对象的大型应用程序上。
从J2SE 1.2开始,虚拟机合并了很多不同垃圾回收算法,并用以分代回收的方式将它们组合起来。比较幼稚的垃圾回收算法会检查每一个在heap中存活的对象,分代回收算法则通过分析和观察那些已经被证实的,能满足大多数应用程序最小化工作的一些特性来声明无用('垃圾')对象。其中最重要的被观察特性就是'弱代假说'(weak generational hypothesis),其含义就是大多数对象只需要存活一小段的时间。
下图中蓝色部分是典型的对象生命周期分布。x轴为对象的生命周期,量度为分配的字节大小。y轴上的字节数是对象总字节数与之相对应的生命周期。
有一些对象确实需要长时间的存活,所以它们的分布区域已经超出图的右侧。例如一些对象在程序初始化的是就被分配空间,当程序结束后才被释放。除了这两种极值以外的是那些存活一段时间的对象。高效的垃圾回收就是要致力于使大多数对象都英年早逝。
为了达到这种优化情况,内存被以代(generation )来管理,换而言之内存池存储着不同'年龄'的对象。垃圾回收发生在不同代被填满的时候。大多数的对象被分配内存的时候,都被发配到了新生代(young generation),并且大多数都终身待在那里。当新生代被填满的,会导致minor collection,此时只有新生代中对象会被回收,其它代中的'垃圾'对象不会被回收。Minor collections可以通过假设弱分代中大多数对象都是'垃圾'并可以被回收来被优化。一些在新生代垃圾回收后存活下来的对象会被转移到老生代(tenured generation)。最终老生代会被填满,然后需要垃圾回收。此时会进行major collection,把整个heap都回收掉。Major collection通常要比minor collection占用更长的时间,因为一大堆对象都要参与回收。
默认的generation被划分成如下图。
当初始化时,最大的内存地址被虚拟化的保留着,不会分配任何物理内存,除非有需要的时候。整个内存地址空间被分为young和tenured代。
新生代由一个eden和两个survivor spaces组成。大多数对象一开始被分配到eden中。一个survivor space一直是空的,用来作为转移eden中的活对象到另一个survivor space中的中转区。活对象在两个区域内不停的交换,直到被转移到老生代。
第三个代和老生代相邻,它叫做用生代(permanent generation),用来保存那些虚拟机描述对象的数据。例如对象描述类和方法定义。
衡量垃圾回收性能主要通过两个指标
生产力指的是没有用在垃圾回收上的时间和总时间的百分比。
暂停 指的是应用程序失去响应的时间,这个时候正在进行垃圾回收。
用户对垃圾回收有不同的需求。例如一个Web服务器应用,垃圾回收时的暂停是可以忍受的,但如果一个图形交互系统有少量的暂停都会影响用户的体验。
J2SE1.4之前,Java虚拟机不支持并行垃圾回收,所以垃圾回收对一个基于多处理器系统的影响很大。下图是一个扩展性很好的系统模型,但是垃圾回收的效率不尽人意。红线是一个只在垃圾回收上使用1%时间的应用程序,当它运行在32个处理器上的系统上是,20%的生产力被浪费掉了。
Ergonomics是在j2se1.5中加入的一个新功能,它可以为一个几乎或者没有通过命令行参数优化的系统提供一个较好的性能表现。它主要通过选择如下项目来实现优化。
- garbage collector 垃圾收集器
- heap size 堆内存大小
- and runtime compiler 运行时编译
当虚拟机启动时,这些选项是以所运行的应用程序的特征来被Ergonomics选择的。通常会已运行当前应用程序行的机器类型作为参考(大的应用程序运行在性能好的机器上)。添加这些选项是最简单的优化虚拟机的方式。
JavaSE平台的一个强项就是避免用户过多的去考虑内存如何分配,然而一但垃圾回收遇到瓶颈,我们对垃圾回收的实现机制有所了解还是很有必要的。垃圾回收器对应用程序使用对象的方式作出一些假设,这些假设反映在那些可调优的参数上。通过调整这些参数,系统的性能能够得到提升,与此同时系统的抽象性不会受到影响。
当一个对象没有任何引用指向它时,它会被当作'垃圾'。最简单直接的垃圾回收算法是遍历所有能够被指向到的对象,所有未被指向到的对象,就当作'垃圾'了。这个算法实现的时间和当前存活对象的个数成正比,因此这种算法被禁止使用在会有很多存活对象的大型应用程序上。
从J2SE 1.2开始,虚拟机合并了很多不同垃圾回收算法,并用以分代回收的方式将它们组合起来。比较幼稚的垃圾回收算法会检查每一个在heap中存活的对象,分代回收算法则通过分析和观察那些已经被证实的,能满足大多数应用程序最小化工作的一些特性来声明无用('垃圾')对象。其中最重要的被观察特性就是'弱代假说'(weak generational hypothesis),其含义就是大多数对象只需要存活一小段的时间。
下图中蓝色部分是典型的对象生命周期分布。x轴为对象的生命周期,量度为分配的字节大小。y轴上的字节数是对象总字节数与之相对应的生命周期。
有一些对象确实需要长时间的存活,所以它们的分布区域已经超出图的右侧。例如一些对象在程序初始化的是就被分配空间,当程序结束后才被释放。除了这两种极值以外的是那些存活一段时间的对象。高效的垃圾回收就是要致力于使大多数对象都英年早逝。
为了达到这种优化情况,内存被以代(generation )来管理,换而言之内存池存储着不同'年龄'的对象。垃圾回收发生在不同代被填满的时候。大多数的对象被分配内存的时候,都被发配到了新生代(young generation),并且大多数都终身待在那里。当新生代被填满的,会导致minor collection,此时只有新生代中对象会被回收,其它代中的'垃圾'对象不会被回收。Minor collections可以通过假设弱分代中大多数对象都是'垃圾'并可以被回收来被优化。一些在新生代垃圾回收后存活下来的对象会被转移到老生代(tenured generation)。最终老生代会被填满,然后需要垃圾回收。此时会进行major collection,把整个heap都回收掉。Major collection通常要比minor collection占用更长的时间,因为一大堆对象都要参与回收。
默认的generation被划分成如下图。
当初始化时,最大的内存地址被虚拟化的保留着,不会分配任何物理内存,除非有需要的时候。整个内存地址空间被分为young和tenured代。
新生代由一个eden和两个survivor spaces组成。大多数对象一开始被分配到eden中。一个survivor space一直是空的,用来作为转移eden中的活对象到另一个survivor space中的中转区。活对象在两个区域内不停的交换,直到被转移到老生代。
第三个代和老生代相邻,它叫做用生代(permanent generation),用来保存那些虚拟机描述对象的数据。例如对象描述类和方法定义。
衡量垃圾回收性能主要通过两个指标
生产力指的是没有用在垃圾回收上的时间和总时间的百分比。
暂停 指的是应用程序失去响应的时间,这个时候正在进行垃圾回收。
用户对垃圾回收有不同的需求。例如一个Web服务器应用,垃圾回收时的暂停是可以忍受的,但如果一个图形交互系统有少量的暂停都会影响用户的体验。