JVM调优分享-(概要+例子)

来源:互联网 发布:网络ip地址怎么修改 编辑:程序博客网 时间:2024/06/06 09:57

堆与

栈是运行时的单位,而堆是存储的单位

1.栈代表了处理逻辑,而堆代表了数据
2.堆中的内容可以被多个栈共享
3.面向对象就是堆和栈的结合

JAVA中堆存的是对象。栈中存的是基本据类型和堆中对象的引用

堆和栈的分离的思想,才使得Java的垃圾回收成为可能

栈代表了处理逻辑,而堆代表了数据。这样分开,使得处理逻辑更为清晰

 堆中存的是对象。栈中存的是基本数据类型和堆中对象的引用

  堆和栈中,栈是程序运行最根本的东西。程序运行可以没有堆,但是不能没有栈。而堆是为栈进行数据存储服务,说白了堆就是一块共享的内存。不过,正是因为堆和栈的分离的思想,才使得Java的垃圾回收成为可能。

    Java中,栈的大小通过-Xss来设置,当栈中存储数据比较多时,需要适当调大这个值,否则会出现java.lang.StackOverflowError异常。常见的出现这个异常的是无法返回的递归,因为此时栈中保存的信息都是方法返回的记录点。


GC时回收的对象

以栈或寄存器中的引用为起点,可以找到堆中的对象,又从这些对象找到对堆中其他对象的引用,这种引用逐步扩展,最终以null引用或者基本类型结束,这样就形成了一颗以Java栈中引用所对应的对象为根节点的一颗对象树,如果栈中有多个引用,则最终会形成多颗对象树。在这些对象树上的对象,都是当前系统运行所需要的对象,不能被垃圾回收。而其他剩余对象,则可以视为无法被引用到的对象,可以被当做垃圾进行回收。


分代垃圾回收

分代垃圾回收采用分治的思想,进行代的划分,把不同生命周期的对象放在不同代上,不同代上采用最适合它的垃圾回收方式进行回收

 虚拟机中的共划分为三个代:年轻代(Young Generation)、年老点(Old Generation)和持久代(Permanent Generation)

 所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)

年老代:

   在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。


分代垃圾回收

Serial: 单线程收集器Serial Old:是Serial收集器的老年代版本

单线程的收集器。它的单线程带来的是:只会使用一个CPU,一条收集线程,并且会在工作时暂停所有的工作线程,直到收集结束。

新生代采用复制算法,老年代采用标记整理算法

ParNew:多线程收集器

Serial收集器的多线程版本,拥有可控制参数(如:-XX:SurvivorRatio, -XX:PretenureSizeThreshold, -XX:HandlePromotionFailure等),收集算法停顿,对象分配规则,回收策略都Serial收集器完全一样

ParNew收集器是许多运行在server模式下的虚拟机中首选的新生代收集器,一个重要的原因是,只有ParNewSerial收集器能和CMS收集器共同工作

ParNew收集器是使用-XX:+UseConcMarkSweepGC选项的默认新生代收集器。也可以用-XX:+UseParNewGC选项来强制指定它。


ParNew收集器在单CPU环境中不比Serial效果好,甚至可能更差,两个CPU也不一定跑的过,但随着CPU数量的增加,性能会逐步增加。默认开启的收集线程数与CPU数量相同。在CPU数量很多的情况下,可以使用-XX:ParallelGCThreads参数来限制线程数。


两个概念需要区分:

Parallel并行:多垃圾收集线程并行工作,但用户线程仍需等待

Concurrent并发:用户线程和垃圾收集同时进行

Parallel Scavenge:复制算法收集器

Parallel Scavenge的特点是它的关注点与其他收集器不同,CMS等收集器的关注点尽可能地缩短垃圾收集时用户线程的停顿时间,而ParallelScavenge收集器的目标则是达到一个可控制的吞吐量Throughput)。所谓吞吐量就是CPU用于运行用户代码与CPU总消耗时间的比值


高吞吐量和停顿时间短的策略相比,主要强调任务更快完成,而后者强调用户交互体验


Parallel Scavenge提供两个参数控制垃圾回收停顿时间:-XX:MaxGCPauseMillis-XX:GCTimeRatio


MaxGCPauseMillis允许的值是一个大于零的毫秒数,收集器将尽力保证内存回收话费的时间不超过设定值。GC停顿时间缩小是以牺牲吞吐量和新生代空间来换取的,也就是要使停顿时间更短,垃圾回收的频率会增加


GCTimeRatio的值是一个大于0小于100的整数,也就是垃圾收集时间占总时间的比率。设为19,则允许最大GC时间就占总时间的5%1/1+19)),默认99.


也被称为吞吐量优先收集器

CMS:获取以最短时间停顿为目标的收集器

Concurrent MarkSweep 获取最短回收停顿时间为目标的收集器,比较理想的应用场景是B/S架构的服务器


基于标记-清除算法实现,运行过程分成4个步骤:


初始标记(需要stopthe world),标记一下GC Roots能直接关联到的对象,速度很快

并发标记,进行GCRoots Tracing的过程。

重新标记(需要stopthe world),为了修正并发标记时用户继续运行而产生的标记变化,停顿时间比初始标记长,远比并发标记短。

并发清除

G1收集器

G1. Garbage first,尚在研发阶段,使用标记-整理算法精确控制停顿,极力避免全区域垃圾收集。前面的收集器进行的收集范围都是整个新生代或老年代,而G1将整个JAVA堆划分为多个大小固定的独立区域,跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先列表,每次在允许的收集时间里,优先回收垃圾最多的区域


JVM调优定义

基于JVM的内存管理垃圾回收机制的特性,通过控制堆内存的各个部分的比例和GC策略来实现JVM性能或业务指标的最优化。


典型应用中,对象的生命周期


横轴是以分配的字节数度量度量的对象生存期。纵轴方向计算的字节数是相应生存期对象的总字节数。左侧的峰值表示分配之后不久就被回收的对象

GC性能对整个系统性能的影响


如何调优


JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数,过多的GC和Full GC是会占用很多的系统资源(主要是CPU),影响系统的吞吐量。特别要关注Full GC,因为它会对整个堆进行整理,导致Full GC一般由于以下几种情况:

Ø旧生代空间不足
调优时尽量让对象在新生代GC时被回收、让对象在新生代多存活一段时间和不要创建过大的对象及数组避免直接在旧生代创建对象 
ØPemanetGeneration空间不足
增大Perm Gen空间,避免太多静态对象 
Ø统计得到的GC后晋升到旧生代的平均大小大于旧生代剩余空间
控制好新生代和旧生代的比例  
ØSystem.gc()被显示调用
垃圾回收不要手动触发,尽量依靠JVM自身的机制 

调优手段主要是通过控制堆内存的各个部分的比例和GC策略来实现

各部分比例不良设置会导致什么后果:

Ø新生代设置过小

  一是新生代GC次数非常频繁,增大系统消耗;二是导致大对象直接进  入旧生代,占据了旧生代剩余空间,诱发Full GC

Ø新生代设置过大

  一是新生代设置过大会导致旧生代过小(堆总量一定),从而诱发Full   GC;二是新生代GC耗时大幅度增加。一般说来新生代占整个堆1/3比  较合适

ØSurvivor设置过小

  导致对象从eden直接到达旧生代,降低了在新生代的存活时间

ØSurvivor设置过大

  导致eden过小,增加了GC频率


实例:

新对象预留在新生代

1.调整新生代的大小来保证
2.调整交换区大小来保证
public static void main (String args[]){byte [] b1,b2,b3,b4;b1= new byte [1024*1024];b2= new byte [1024*1024];b3= new byte [1024*1024];b4= new byte [1024*1024];}


使用
-XX:+PrintGCDetails -Xmx10M -Xms10M 和-XX:+PrintGCDetails -Xmx10M -Xms10M-Xmn6M
区别



例2:

大对象直接进入老年代

1.直接调整对象大小

-XX:PretenureSizeThreshold=1000000

public static void main(String args[]){byte [] b1;b1= new byte[1024*1024];}


使用-XX:+PrintGCDetails -Xmx20M -Xms20M和-XX:+PrintGCDetails -Xmx20M -Xms20M-XX:PretenureSizeThreshold=1000000


例3:

1.堆大小是否要设置成一置呢?

稳定的堆大小可以减少GC的次数

GC时间长

2.GC时,如果堆的空间比较小,可以减少时间

    -XX:MinHeapFreeRatio=40

    -XX:MaxHeapFreeRatio=50

public static void main(String args[]) throws InterruptedException{Vector v =new Vector();while(true){byte [] b = new byte [1024*1024];v.add(b);if(v.size() ==10 ){v = new Vector();}Thread.sleep(1000);}}





0 0