JVM调优

一,内存结构

程序计数器:线程私有,每个用于每个线程存储和标记自己的执行的程序号行,字节码解释器可以通过改变这个来让线程进行执行、调用和恢复程序等。

栈:线程私有,每个线程在执行过程中都有一个栈,每次调用方法就会创建一个栈帧,里面包括了局部变量(基本类型以及对象引用),方法出口信息等。若代码中的调用深度很大以及局部变量很多,需要适当增大此大小,

堆:线程公用,所有对象创建皆在与此分配内存。具体对象模型分2种,一种是创建了一个句柄池,栈存储堆中对象的句柄地址,句柄中存储到实际对象的指针。另一种是栈中引用直接指向实际对象地址。大部分虚拟机都是用第二种。

方法区:逻辑上属于堆,但是实际不是堆的一部分,别名为非堆。线程公用,用于存储所有类的信息、编译代码、常量、静态变量。虽然为持久代,但是还是会被回收,只是条件比较苛刻。

运行时常量池:方法区的一部分,用于存储一些运行时创建的常量。string.inter方法是将常量强制放入其中的显式调用。

本地方法栈、直接内存等如名称所义。

 

二,GC工作机制

1,哪些需要回收?

一种为引用计数器的方式。每有一个引用就+1,引用为0就GC。互相引用时容易出问题。

一种为根节点搜索的方式。定义所有栈中的变量表中的引用的对象、方法区中静态属性及常量引用的对象、本地方法栈中引用的对象为根对象,遍历堆中对象,所有没有到达到根节点的对象均需回收清理。绝大部分都是使用此方式进行判断。

2,怎么回收?

a)标记清除

通过根节点搜索,找出所有要回收的对象,将其一一清除,释放内存。缺点:慢,以及容易产生内存碎片。

b)复制

将所有不要回收的对象复制到另一块内存,其他的全部清除。缺点:需要多担保一块内存来进行复制使用。

c)标记整理

将所有不需要回收的对象都向一端移动,然后一次性清除端边界以外的所有对象。一般是有很多对象不回收时,使用此方式,如老年代,因为年轻代对象死太快了,整理的话,移动太多,不如直接复制就好。

d)分代收集

并不是另外的清除方式,二十依据大部分对象存活时间短的特性,将内存划分为年轻代、年老代、持久代,不同类型使用不同方式清除。

年轻代用于优先存储新创建的对象,分为一个Eden区和2个surv区,默认比例是8:1:1,每次执行年轻代GC时,将所有内存拷贝到其中一个存活区,其他全部clean,2个存活区交替使用。本质其实是使用复制的方式回收内存。

年老代,一般作为年轻代的担保,以及一些年轻代回收了很多次还在内存中的对象存储。使用标记整理或者标记-清除-压缩整理的方式执行回收。

持久代,常量等。回收方式不知,但是确实有回收。

3,何时回收?

当前大部分虚拟机都是使用分代收集方式进行回收,所以年轻代回收时机是请求内存时,年轻代不够内存分配了,就会执行年轻代GC。年老代不够用(到阈值)了就会执行FullGC(可怕,都不管年轻代够不够)。年轻代内存不够时,老年代如果担保内存也不够,也会提前出发fullGC。持久代到阈值也会FullGC。

这些阈值默认1.5及以前都是68%,1.6及以后为92%。

 

三,垃圾回收器

1,Serial串行垃圾回收器(年轻代)

停止所有用户线程,执行GC。复制算法。

2,ParNew并行垃圾回收器(年轻代)

停止所有用户线程,多线程并行执行GC。复制算法。

只有年轻代使用此收集器,老年代才能用并发收集器。

3,Parallel Scavenge并行垃圾回收器(年轻代)

可以指定停顿时间占比等,主要用于重视CPU执行时间的吞吐量优先服务器。还可以设置堆内存各部分占比自动分配。但是堆总内存需要另外指定。复制算法。

年轻代使用此收集器时,老年代除了串行就只能使用ParallelOld。

4,Serial Old老年代串行回收器(老年代)

同1。标记-整理算法。

5,Parallel Old老年代并行垃圾回收器(老年代)

同3。标记-整理算法。

与3完美搭配。可直接设置UseParallelOldGC一次性指定3和5.

6,CMS并发收集器(老年代)

停止所有用户线程,第一次标记所有可以直接到GCROOT的对象-->恢复线程,产生并发GC线程,对剩余线程进行标记-->停止所有线程,对上一步并发时产生的对象进行标记,得到所有不被回收的之后,其他对象则为需要回收的,标记之-->恢复线程,清除上一步标记的所有需要清除的对象。标记-清除算法。

设置此收集器时,年轻代默认使用2,并行收集器。

标记清除算法容易产生内存碎片,所以需要进行内存整理,即内存压缩。jvm有参数可以指定fullGC多少次之后压缩一次。

7,G1垃圾回收器(年轻代)

1.6很后的版本以上jdk才支持,将内存分为多个块,哪块垃圾多,就对哪块进行标记-整理。回收时机受参数影响。

 

四,JVM调优工具

1,jstack,导出线程快照。jstack [pid] >> [pathfile]。

2,jmap,导出堆栈内存快照。jmap -dump:live,format=b,file=[pathfile] [pid]。

3,jstat,可以查看GC执行情况。jstat -gcutil [pid] 1000 100。

-gcutil为GC统计使用的百分比,-gc为每次获取GC工作快照中内存详细容量。1000为毫秒数,每隔几秒收集一次GC工作信息,100为收集多少次。

4,jhat、IBM AnalyzeMemory、VisualVM。用于对jmap导出的heap快照文件进行profiling(性能分析)。

注意运行运行内存的设置。

 

五,JVM调优步骤

1,使用ps-ef|grep java命令得到具体的Java进程的pid。

2,使用top命令,确定是哪个pidCPU占用过高。

3,使用top -p[pid] -H命令,得到java进程中是哪些哪些线程在占用大量资源,记录其pid。

4,进入java的bin目录,cd /usr/java/jdk*/bin。

5,执行jstat查看GC情况。

6,执行jstack导出线程快照。

7,执行jmap导出堆栈快照。

8,分析GC情况,看看是不是哪里内存无法回收。或者频率过高、过久。

9,分析jstack线程快照中第三步占用资源多的线程在执行什么。看是GC方面还是具体业务代码的问题。

10,分析jmap导出的heap文件,使用visualVM工具或者IBM的工具分析,注意指定运行内存。得到内存占用过大的对象。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值