java Jvm GC流程以及内存问题排查调优

作者:转载或者引用请注明出处!

首先梳理一下JVM虚拟机的内存布局:

    JDK版本<1.8 :
                拿线程是否可以共享作为分类:1. 被所有线程共享【 方法区(含运行时常量池),堆 】    2. 线程私有【 JVM虚拟机栈,本地方法栈,程序计数器 】

    JDK版本>=1.8  : 
                拿线程是否可以共享作为分类:1. 被所有线程共享【 堆(运行时常量池),元空间 】    2. 线程私有【 JVM虚拟机栈,本地方法栈,程序计数器 】


    再来梳理一下JVM的GC流程(以及gc需要知道的细节):

            JDK1.8 : 使用的虚拟机版本 Hotspot 
                
              1. 对象是如何判断死亡还是继续生存?
                        目前使用可达性分析方式,因为引用计数的方式解决不了对象相互引用的问题。
                        首先可以作为root根节点的对象为4类:静态对象,常量对象,当前栈帧对象,JNI对象

                       目前jvm判断对象是否可以被回收的方法是通过枚举GCroots的根节点,进行准确式GC(准确式内存管理+GC回    收)。判断当前对象到root根节点是否 可达(root节点引用其他对象,其他对象引用当前对象),则该对象不会回 收,继续生存。 不可达  (当前对象到root节点找不到间接或者直接的引用关系),则回收


                2.判断完成后如何进行回收?
                        回收之前必须经过2次标记才能将对象内存彻底释放。
                            1)第一次标记
                                  该对象没有到GCroot节点的引用关系,则进行标记
                            2)第2次标记是判断finalize()方法是否执行?
                                 只有在被重写的情况下才有被执行资格,可以并且只执行依1次,重写过并没有执行过,则放入一个低优先                    级线程的队列中(该队列执行被放入的对象的finalize方法),对象逃逸/自救 未成功,则进行二次标记。


                 3.什么叫做安全点?

                          由于gc的时候对“一致性”要求比较敏感( 一致性:说的是stop the word的时候,对象状态在当前时间下的引用状态不会轻易变化),而且同时也为了减少oopmap的空间成本。所以按照"当前代码段运行时间长,而且对象引用状态比较稳定"的条件,选取一些特定的点,这些点就是安全点。来告诉回收器,到代码运行到安全点的时候,对象状态什么的比较稳定,可以stop the word操作,有利于jvmGC。

                            常用于安全点的地方:  异常,方法返回等时间相对对对象引用影响较少的运行时机


                    4.什么叫做安全域?

                            基于安全点的概念,在真实情况中,线程可以挂起,阻塞等异常状态出现,导致到达不了安全点。二stop the word的规则就是等到所有线程都到了各自的安全点挂起才能进行GC。为了防止这种情况发生,就搞了一个域的概念,包裹的是代码块。在一些阻塞或者等待等方法前后包裹起来的代码块。叫做安全域。当代码进行安全域的时候,JVM查询各线程状态的时候,这个线程会告诉jvm,我在安全域,不影响你GC。然后jvm就不再去理会该线程,开始GC,当该线程代码准备出安全域的时候,回去询问jvm,你那边gc完事了没有,没有我再等一会。

                     5.主动式中断和抢先式中断

                          1).抢先式中断不需要线程代码主动配合,当GC发生时,首先把所有线程中断,如果发现线程中断的地方不在安全点上,就恢复线程,让他跑到安全点上。现在几乎没有虚拟机实现采用抢先式中断来暂停线程来响应GC。 

                                2). 主动式中断的思想是当GC需要中断线程的时候,不直接对线程操作,仅仅简单的设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起,轮询标志的地方和安全点是重合的另外再加上创建对象需要分配的内存的地方。

                            6.gc枚举时oopmap的作用。

                    oopmap在JIT编译器,类加载完成时候,会记录对象内什么偏移量是什么类型的数据。这样方便后面gc的时候可以快速定位对象的类型以及引用位置,提高枚举根结点的速度。jvm不会为每一条对象变化的指令生成oopmap,只有在安全点和安全域的时候。

           

    
DSAD
    SAD 
(())
                    

                        

                




服务架构采用的是多线程并行的master+多台worker集群。

任务内容是进行流数据的传输。所以涉及到很多byte[]的创建以及复制拼接。

报错但是未能在日志查询具体原因,经过排查,DirectMemory内存不足导致。发现自己原来在代码里面操作byte[]对象时候,采用的是System    相关操作字节对象的API。System使用的是本地内存。解决方式:改为Arrays相关的API进行操作,这样由原来直接内存的使用转换到了jvm内存上。

猜你喜欢

转载自blog.csdn.net/PioneerX_x/article/details/80349107