从一次FULL GC说起 (一)


声明:本文转载自https://my.oschina.net/chener/blog/1574318,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

      前几天突然收到一堆报警短信,吓得赶紧打开电脑查看日志,发现JVM不断做FULL GC,于是赶紧让运维重启服务器,接口监控提示一切正常。

      废话不多说,想要了解jvm的gc那得先说说jvm的内存结构:

  • 程序计数器

      记录每个线程执行到哪条字节码指令,解释器通过它来选取下一条执行的字节码指令,线程私有。

  • java栈

      以栈帧为单位,进行压栈和出栈,线程私有。栈帧存储了方法的局部变量表、操作数栈、动态链接和方法的返回地址等信息。每一个方法从调用开始直至执行完成的过程,都对应的一个栈帧在虚拟机栈里入栈和出栈的过程。每次方法调用均会创建一个对应的Frame,方法执行完毕或者异常终止,Frame被销毁。一个方法A调用另一个方法B时,A的frame停止,新的frame被创建赋予B,执行完毕后,把计算结果传递给A,A继续执行。JVM Statck的大小可以是固定的,也可以是动态扩展的。如果线程需要一个比固定大小大的Stack,会发生StackOverflowError;如果动态扩展Stack时没有足够的内存或者系统没有足够的内存为新线程创建Stack,发生OutOfMemoryError。参数-Xss用来设置虚拟机栈的大小。

                                

  • 本地方法栈

       为native方法服务,线程私有,有可能和虚拟机栈合二为一。

       jvm内存中最大的一块,线程共享,用来分配对象实例,数组。GC回收的主要区域,根据GC回收机制又可以分为年轻代和老年代。-Xms,初始使用,默认物理内存 1/64。-Xmx,最大内存,默认物理内存 1/4。虚拟机会根据堆的空闲情况动态调整推大小,空余大于 70%,会减少到 -Xms,空余小于 40%,会增大到 -Xmx。所以服务器如果配置 -Xms = -Xmx,则可以避免堆自动扩展。

  • 方法区

       主要存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据(比如spring 使用IOC或者AOP创建bean时,或者使用cglib,反射的形式动态生成class信息等),线程共享。

       关于这边有个有意思的东西:

Integer a=1; Integer b=1; Integer c=new Integer(1); System.out.println(a==b);//true System.out.println(a==c);//false 

      而我们知道==判断基本类型的时候是判断值相等,判断类的时候判断地址相等。那为什么会出现这种情况呢?因为Byte,Short,Integer,Long,Character,Boolean这5种包装类默认创建了数值[-128,127]的相应类型的缓存数据放进了常量池,但是超出此范围仍然会去创建新的对象。 两种浮点数类型的包装类Float,Double并没有实现常量池技术。

      所以从上面的解释我们可以有一个jvm内存结果的图:

                     

       在对jvm 内存的了解后,我们知道Java 堆中存放着几乎所有的对象实例,但是资源是有限的,所以我们需要对对象进行回收。垃圾收集器对堆中的对象进行回收前,要先确定这些对象是否还有用,判定对象是否为垃圾对象有如下算法:

  • 引用计数算法

      给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加 1,当引用失效时,计数器值就减1,任何时刻计数器都为 0 的对象就是不可能再被使用的。引用计数算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的选择,但是Java语言并没有选择这种算法来进行垃圾回收,主要原因是它很难解决对象之间的相互循环引用问题。

  • 根搜索算法

      这种算法的基本思路是通过一系列名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连时,就证明此对象是不可用的。在 Java 语言里,可作为 GC Roots 的兑现包括下面几种:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  2. 方法区中的类静态属性引用的对象。
  3. 方法区中的常量引用的对象。
  4. 本地方法栈中 JNI(Native 方法)的引用对象。

      一般情况下,在垃圾回收期间,一个无法触及的对象会立即被销毁。不过,覆盖了finalize()方法的对象会被移动到一个队列里,一个独立的线程遍历这个队列,调用每一个对象的finalize()方法。在finalize()方法调用结束之后,这些对象才成为真正的垃圾,等待下一轮垃圾回收。

    

      

 

本文发表于2017年11月16日 14:33
(c)注:本文转载自https://my.oschina.net/chener/blog/1574318,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 3250 讨论 0 喜欢 1

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1