这是一个与众不同的JVM

我看过一本关于JVM的书,根据自己所看的所得,写下这篇文章。

                                                                     -----------------------------------------------个人见解,如有不足,见谅。

 

  1.  jvm为什么分代回收

           因为不同区域代的对象存活的时间不同,有的老年代获得久,发生GC的次数就比较少,像年轻代,对象生命周期短,发生垃圾回收的次数久多。每进行一次垃圾回收,都会都区域内的对象整体进行遍历,遍历很耗时。进行分代回收,可减少对象遍历的次数,个数。根据对象存活时间选择不同的回收算法,收集器,提高效率。

       

   2.什么时候发生垃圾回收

        先说jvm的区域。

          1.年轻代,ScanvengeGc发生频繁,当有对象申请空间时,Eden区满了,会进行一次垃圾回收,将存活的对象复制到survivor区内。发生一次。这个垃圾回收频繁,需要使用效率高的回收算法

回收的对象是垃圾对象,什么是垃圾对象:没有引用指向的对象。

静态变量引用的对象,方法执行过程中引用的变量不能回收。

怎么回收:就是回收算法

         2.FullGc是对整个堆,进行的。发生在老年代写满,永久代写满。

            显示调用,上一次GC之后Heap的各域分配策略动态变化,发生次数少,比较耗时。

我们把我们的项目打成包,部署到服务器(tomacate),当服务器启动的时候,jvm会启动进程,通过类加载器把我们的类加载到jvm内存,存到元数据区(存放类信息)

服务器启动的时候,会启动spring容器,实例对象。反射技术。


一次请求过程的jvm情况?

  当服务器有请求过来,会有线程执行请求,线程执行请求在jvm内存有独享的工作内存空间,栈内存。

然后执行对象中的一些方法,执行方法过程中,会有局部变量,引用对象,局部变量放在线程的栈内存中,会有执行方法的栈帧,局部 变量放到栈帧的局部变量表里面,也可能会创建对象,栈帧里面的引用,会引用对象。方法执行完,栈帧弹出去。

栈,先入后出,先入栈的压到最尾,出去从栈头出。

jvm运行起来,对象怎么分配的?

一个程序,方法main是入口 ,一个main线程执行程序代码。创建对象

而我们的应用:像spring,会初始化一些bean,这些bean的实例化,就是有工作线程进行创建bean实例,执行代码。业务逻辑。

3.内存划分

 jvm内存8以后,元数据区就是以前的永久代,存放类信息。常量池放置到了堆内存。

年清代和老年代通称堆。默认eden:s1:s2=8:1:1

每个方法执行,都会创建相应的栈帧执行对应的方法,每个栈帧有局部变量表,存储变量

4.老年代如何进行回收垃圾(算法和垃圾收集器)

4.1   由于老年代的对象都是存活比较长的,大部分都是需要一直存活的(spring的bean),少量回收的。所以不适合使用复制算法,占用空间。采用标记清除(内存碎片,大对象碎片无法存放,浪费空间)不行。标记-整理合适。

算法:标记-整理

4.2  垃圾收集器

    使用并发收集:减少应用停顿,发多核cpu.但是由于应用没有停止,会导致垃圾回收不彻底。还要运行垃圾回收线程,需要设定运行线程的空间,不然也会造成应用停止。

    jdk8之前:parellNew+cms收集器,    jdk9以后:g1收集器

   parellNew:年轻代

   cms:分阶段,




5.垃圾回收算法

6.垃圾收集器

串行收集器:单线程,应用线程会停止。无法发挥多核cpu的优势。安全,利用这个开启 -XX:+UseSerialGC

 并行收集器:多线程,年轻代使用,减少收集时间。应用停止

 并发收集器:应用不停止,减少应用停顿时间。利用处理器减少应用停顿的时间。

       由于是在应用线程不停止的情况下,会在收集完后,有剩余的垃圾没有回收,收集中,应用产生的。需要设置预留空间20%,供这些使用

      由于需要运用垃圾回收的线程,需要有足够的内存空间,如果收集时,堆满了,会出现Concurrent Mode Failure,造成应用停止,只进行垃圾回收。

  。通过设置-XX:CMSInitiatingOccupancyFraction=<N> 指定还有多少剩余堆时开始执行并发收集。

增量收集器:采用划分区域的方式,不是针对整个堆进行回收,针对区域回收,采用复制算法。将存活对象最少的区域进行复制回收。实现边回收边使用的效果。


总结:

     串行:数据量小,小型应用

      并行:大型web,响应时间没有要求,多核cpu,应用吞吐高。:后台处理、科学 计算。

     并发:应用需要响应时间长。大中型应用Web服务器/应用服务器、电信交换、集成开发环境。

   老年代一般是:并发收集器,要考虑内存碎片的问题

    年轻代一般使用的是,并行收集器。也可与设置老年代并行收集器


7.调优

  年轻代的大小:

    总结:设置大点:减少对象到达老年代的数量,减少yongGc。

    解析:吞吐高的,年轻代尽量设置大些,减少垃圾回收的次数,减少对象到达老年代的机会。使得老年代都是永久对象:可能到达Gbit的程度。因为对响应时间没有要求

     响应时间快的,年轻代也设置大些,减少发生gc。尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)

  老年代大小

    吞吐量:设置大的年轻代,小的老年代。

   响应时间优先:老年代使用的是,并发收集器。要合理设置堆的大小,减少内存碎片的产生(可通过设置多少次Gc进行内存碎片的整理)。堆大了,收集的时间长。

8.垃圾回收的瓶颈

    由于并行收集,提高了应用的吞吐量,但是会带来应用的暂停,很大程度上,对一些实时性要求较高的应用无法满足。

   虽然jvm提供了相应的并发收集器,但是并发收集器会产生内存碎片的问题。并且也不能完成保证用用不暂停。并且是针对整个堆进行回收的,     无法分代回收,在暂时时间的控制上还是和弱的。

    需要解决,内存碎片和响应时间的瓶颈:增量收集器,不能精确控制停顿时间


  增量收集器:通过将堆内存进行划分不同的region区域。每次使用部分区域,通过标记复制进行回收对象,并且,对region里面存活对象最少的进行复制,将存活的复制到另一个空的region。

  这样不是回收的整个堆,可以实现边回收,边使用

Garbage Firest  G1算法回收 JDK 7 登场

G1吸收了增量GC以及CMS的精髓,将整个jvm Heap划分为多个固定大小的region,扫描时采用Snapshot-at-the-beginning的并发marking算法(具体在后面内容详细解释)对整个heap中的region进行mark,

回收时根据region中活跃对象的bytes进行排序,首先回收活跃对象bytes小以及回收耗时短(预估出来的时间)的region,回收的方法为将此region中的活跃对象复制到另外的region中,根据指定的GC所能占用的时间来估算能回收多少region,

这点和以前版本的Full GC时得处理整个heap非常不同,这样就做到了能够尽量短时间的暂停应用,又能回收内存,由于这种策略在回收时首先回收的是垃圾对象所占空间最多的region,因此称为Garbage First。

cms收集器也是并发收集器(current mark sweep):是为了减少应用停顿时间的收集器。但是用的算法是标记清除,会产生大量的内存碎片。

G1收集器:采用的是标记整理,不会产生内存碎片,可以精确控制停顿时间。


生产环境tomcate里面jvm怎么设置参数的?怎么检查jvm运行情况?

如果是javaweb部署到timcate里面,jvm是tomcate的一个进程,你的系统是tomcate里面jvm进程运行的

需要看tomcate的一个脚本。

jvm参数包括:内存大小的分配,栈,元数据,堆(年轻(eden,surivor),老年),垃圾收集器的配置,每种垃圾回收器的特殊参数

根据每秒请求的数量,请求创建的对象,预估下大小。会在eden去创建多少对象,触发yongGc的频率,老年代的存活多少对象,压测,观察jvm运行情况。jstat工具查看jvm情况,观察:

  eden对象增长情况,yongGc频率,eden存活对象多少,sur能否放下,老年代的对象增长速率,老年代fullGc的发生时间。

根据情况去调节jvm。

压测内容:

接口性能,一个系统的QPS,压测一定程度时的cpu,IO,磁盘的使用情况,jvm表现。


GC优化

知道预估,知道工具调节设置jvm参数。实际有遇到过jvm线上fullGc频繁吗,导致系统卡顿?

如果实际没有发生过,就说,是通过压测搞得。结合业务


发生oom后如何排查

首先在jvm参数的里面可以设置,发生oom异常的时候,复制一份内存使用情况的快照。可以根据快照情况去查看哪些对象(占用内存最大的对象)造成的oom异常。在找到对应的代码行,进行代码的优化。

说自己的项目业务中,什么情况下发生了报警,客户反映功能不能用。

并发导致(非代码)。

内存泄漏:代码对象无法回收。

内存溢出:超高并发时,瞬间创建大量对象,没有足够的空间存放。


jvm什么时候发生栈溢出?

1.当线程请求栈的深度大于该栈的深度时,会发生栈内存溢出。一般递归调用产生

2.栈动态扩展之后,还是不能申请足够的空间去存放,就会发生。一般是多线程调用的时候

-Xss512k 是栈的大小


Survivor的存在意义,就是减少被送到老年代的对象

每熬过一次Minor GC,年龄+1   经过15次, 若年龄超过一定限制(15),则被晋升到老年态。

JVM的配置参数

   -server -Xms3800m -Xmx3800m -Xmn1500m -Xss512k 

    -XX:+UseConcMarkSweepGC

   XX:+UseParNewGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection -XX:+CMSClassUnloadingEnabled    -XX:+DisableExplicitGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

-Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/logs -Dcloudengine_tr_min_pool_size=100

 xms最大堆大小, -Xmx3800m 初始堆大小

-Xmn1500m年轻代大小    -xss 线程栈的大小

XX:+UseConcMarkSweepGC  设置老年代为并发收集器,由于老年代并发收集器会产生内存碎片,

XX:+UseParNewGC -XX:CMSFullGCsBeforeCompaction=5 并行收集器5次收集后,进行垃圾内存整理

-XX:+UseCMSCompactAtFullCollection  对老年代的压缩,影响性能,消除内存碎片




CMS的几个阶段?

    1.初始标记,stop the word

    2.并发标记 :与用户线程共同运行

    3.预清理:

    4.可被终止的预清理

    5.重新标记 stop the word

    6.并发清除

   7.并发重置状态等待下次CMS的触发

初始标记?

   标记年轻代中存活的对象引用到老年代的对象

  标记老年代的GcRoot对象 

GC Roots对象?

    虚拟机栈(栈桢中的本地变量表)中的引用的对象

    方法区中静态属性引用的对象

    常量引用的对象

    本地方法栈中JNI的引用的对象

并发标记

     在初始标记的所有存活对象中进行标记,和用户线程一起运行.对于已经经过初始标记的对象

     由于并发运行,会产生新的对象在年轻代,或者年轻代晋升到老年代的对象.这些对象有可能忘记漏标,

      为了减少重复标记,会将这些对象所在的card标记一个dirty.后续处理只需要针对dirty的,不用扫描整个老年代


预清理阶段?

  由于上述阶段不能完全标记出所有存活的对象.这一阶段处理上一阶段由于引用关系改变标记成card的dirty的对象.

  将这些对象标记成存活对象


可终止的预处理

  为了减少清理垃圾对象的负担.此阶段可以在年轻代发生Ygc,减少重新标记,减少年轻代对象引用指向老年代的对象

  最大持续5s


重新标记

  标记整个老年代的存活对象.重新标记的内存范围是整个堆.

  标记年轻代的原因:是因为如果老年代的对象被年轻代的对象引用,将视为存活对象

  年轻代的不可达对象,也会作为GcRoot对象扫描老年代. (因此对于老年代来说,引用了老年代中对象的新生代的对象,也会被老年代视作“GC ROOTS”)

  重新标记前,先年轻代发生一次yGc,将存活的对象到suvovir中,在进行扫描年轻代时,就只扫描sur区就行


并发清理

  清理老年代所有未标记的对象并且回收空间,

  由于和用户线程并行,会产生新的垃圾对象,称未浮动垃圾

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容