JVM学习总结

2 篇文章 0 订阅

参考链接:http://www.cnblogs.com/leefreeman/category/1058724.html

JVM基本结构

  可能通过上面的描述,大家对JVM运行流程有了一个粗略的认识,那么JVM内部到底是怎么执行一个class文件的呢,也就是上图中最后一步第6步的内部细节是怎样的呢?要了解这个问题,我们首先得看一下JVM的内部结构:

image

  从这个结构不难看出,class文件被jvm装载以后,经过jvm的内存空间调配,最终是由执行引擎完成class文件的执行。当然这个过程还有其他角色模块的协助,这些模块协同配合才能让一个java程序成功的运行,下面就详细介绍这些模板,它们也是后面学习jvm最重要的部分。

内存空间:

JVM内存空间包含:方法区、java堆、java栈、本地方法栈。

方法区是各个线程共享的区域,存放类信息、常量、静态变量。

java堆也是线程共享的区域,我们的类的实例就放在这个区域,可以想象你的一个系统会产生很多实例,因此java堆的空间也是最大的。如果java堆空间不足了,程序会抛出OutOfMemoryError异常。

Java栈是每一个线程的私有的区间,它的生命周期与线程是相同的,一个线程对应一个Java栈,每次执行一个方法就会往栈中压入一个元素,这个元素叫“栈桢”,“栈桢”包括局部变量、用于存放中间状态值的操作栈。如果Java栈空间不足来,程序会抛出StackOverflowError异常,一般在线程比较多杭州递归调用方法很分深的情况,会占用大量的栈空间,会产生栈溢出的情况。

本地方法栈和Java栈类似,只是它用来表示执行本地方法,本地方法栈存放的方法调用本地方法接口,最终调用本地方法库,实现与操作系统、硬件交换的目的。

PC寄存器,说到这里,类,静态变量加载到方法区来,实例对象加载到Java堆来,方法加载到Java栈来,各自多去来各自该去的地方。又如何执行这些程序呢,其中PC寄存器中保存来程序执行的指令,它是控制程序指令的执行顺序。

执行引擎是执行PC寄存器分配该它的指令,指令的执行者。

垃圾回收算法

引用计数法

就是堆一个对象被引用的次数进行计算,当增加一个引用计算就加1,减少一个引用计算就减1.

如果计数器为0则表示该对象没有引用,则把该对象清除。

引用计算算法简单,但是Java没有用这种算法,因为这种算法不能删除循环引用,例如 A引用B ,B引用A这种情况,对象是不能被清除的。

标记清除

遍历所有的GC roots , 并从GC roots 科大的对象设置为可存活对象;然后变量堆中所有对象,把没有标记为存活的对象清除;

总结标记清除算法: 因为涉及到大量内存遍历工作,需要停在其他应用,需要的时间比较长,Java吞吐量比较低。

对象被清除自豪,被清除的对象留下内存空缺位置,造成内存不用连续,空间浪费了。

标记压缩算法:

标记压缩算法是在标记清除算法的基础上进行改进的。执行完标记清除操作之后,然后第一内存空间进行压缩,节省来内存空间,解决来标记清除算法内存不连续的问题。注意标记压缩算法也会产生“stop the world”,不能和java程序并发执行。在压缩过程中一些对象内存地址会发生改变,java程序只能等待压缩完成后才能继续。

复制算法:

负责算法是把内存空间一分为二,在垃圾回收的时候,遍历其中一块有对象的内存块,把可存活的对象迁移到另为一块内存区,然后把留有没有迁移的对象区域清空,完成垃圾回收。

复制算法相对压缩算法更简洁高效,但是也是有缺点也是显而易见,不适合用于存活对象多,因为那样需要复制的对象很多,复制性能较差,所以复制算法往往用于内存空间中新生代的垃圾回收,因为新生代中存活对象较少,复制成本较低。它另外一个缺点是内存空间占用成本高,因为它基于两份内存空间做对象复制,在非垃圾回收的周期内只用到了一份内存空间,内存利用率较低。

垃圾回收器可以看做一系列算法的不同组合,在不同的场景使用合适的垃圾回收器,才能起到事半功倍的效果。

垃圾回收器

Java堆的结构:

Java堆内存结构包括:新生代,老年代,其中新生代由一个伊甸区和2个幸存去组成,2个幸存区是大小相同,完全对称,没有任何差别的。我们把他们称为from区和to区。

JVM的垃圾回收主要是针对以上堆空间的垃圾回收。

下面是垃圾回收器。

串行收集器:是gc单个线程对进行垃圾回收,其中新生代使用复制算法,老年代使用标记压缩算法。

gc单线程进行垃圾回收时,其他应用线程需要暂停,只用垃圾回收完之后,其他应用线程在继续运行。

串行垃圾回收器,回收时间比较长,但是相比其他回收器,其稳定性比较好。

并行垃圾回收器:

并行回收器是在串行回收器基础中改进,是用gc多线程并发进行垃圾回收。并行回收器有两种

1、 ParNew回收器

这个回收器只针对新生代进行并发回收,老年代依然使用串行回收。回收算法依然和串行回收一样,新生代使用复制算法,老年代使用标记压缩算法。在多核条件下,它的性能显然优于串行回收器,如果要使用这种回收器,可以在启动参数中配置:

-XX:+UseParNewGC

如果要进一步指定并发的线程数,可以配置一下参数:

-XX:ParallelGCThreads

ParNew回收器的流程如下图所示:

clip_image006

在进行垃圾回收时应用程序线程依然被暂停,GC线程并行开始执行垃圾回收,垃圾回收完成后,应用程序线程继续执行。

2、 Parallel回收器

依然是并行回收器,但这种回收器有两种配置,一种类似于ParNEW:新生代使用并行回收、老年代使用串行回收。它与ParNew的不同在于它在设计目标上更重视吞吐量,可以认为在相同的条件下它比ParNew更优。要使用这种回收器可以在启动程序中配置:

-XX:+UseParallelGC

Parallel回收器另外一种配置则不同于ParNew,对于新生代和老年代均适应并行回收,要使用这种回收器可以在启动程序中配置:

XX:+UseParallelOldGC

Parallel回收器的流程和ParNew的流程是一致的:

clip_image008

在进行回收时,应用程序暂停,GC使用多线程并发回收,回收完成后应用程序线程继续运行。

多线程回收比单线程回收效率高。

cms回收器:

cms回收器是一个只能针对老年代的回收器。它是采用标记清除算法。其他应用线程不用暂停,cms回收线程可以和其他应用线程并行运行,其他回收线程遍历内存区中对象,对有应用可到达的对象标记为存活,多次对对象进行标记,把那些对象标记为不存活的对象清除掉。

cms回收器有一个有不足的地方就是 每次的清理的不彻底,所以会频繁的进行GC线程操作,影响来其他应用线程的吞吐量。

G1回收器:

G1回收器不同与其他回收器,它是将堆空间划分为多个独立的区块,每一个区块既有属于老年代的,也有属于新生代。并且每类区域空间可以是不连续的。每一块区域中需要回收的对象多少不同,G1会优先把多的垃圾区进行回收,这用可以用少量的时间回收更多的垃圾对象。

G1相对cms回收器优点:

1.因为划分很多区块,回收是减少来内存碎片的产生;

2.G1适用新生代和老年代,而cms只适用老年代。

参考链接:http://www.cnblogs.com/leefreeman/p/7509278.html


对jvm故障排查流程:

image

案例:

1.通过jps命令查看服务是否正常运行。

2.通过top命令查看进程使用cpu  内存以及负载情况。

3.如果以上多正常,说明是堆内存是正常的,所以坚持线程栈。

4.使用jstack命令导出线程栈信息。

下面介绍jdk自带的使用工具:jsp jstat  jmap  jstack

jsp 列出目前服务器上运行的Java程序及进程id;

jstat 用于输出Java程序内存使用情况,包括新生代,老年代,元数据容量、垃圾回收情况等。

jmap:用于输出java程序中内存对象的情况,包括有哪些对象,对象的数量。

jmap -histo 3618

上述命令打印出进程ID为3618的内存情况。但我们常用的方式是将指定进程的内存heap输出到外部文件,再由专门的heap分析工具进行分析,例如mat(Memory Analysis Tool),所以我们常用的命令是:

jmap -dump:live,format=b,file=heap.hprof 3618

将heap.hprof传输出来到window电脑上使用mat工具分析:

{U[6FUIMFB%~8B~ZWC9C(RL

jstack:用户输出java程序线程栈的情况,常用于定位因为某些线程问题造成的故障或性能问题。

jstack 3618 > jstack.out

上述命令将进程ID为3618的栈信息输出到外部文件,便于传输到windows电脑上进行分析。


内存溢出原因: 堆内存溢出、元空间、线程栈、直接内存。

堆内存OOM

使用内存超过来申请的堆内存,则想方法增加堆内存空间,在时间开发中有必要去掉引用关系。

元空间OOM

代码循环参加class ,大量class元数据,存放在元数据区超过设置的4M空间,在元空间溢出

栈OOM

当创建的线程是jvm会给每一个线程分配栈内存,当创建线程过多;占用的线程也就越多,这中情况会导致栈OOM

直接内存OOM

ByteBuffer的allocateDirect方法可以申请直接内存,当申请的内存超过的本地可用内存时,会报OOM:











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值