为什么80%的码农都做不了架构师?>>>   

想做architect,就必须对JVM的性能有所了解。JVM的内存管理是性能的一大瓶颈。JVM的性能调优,必须建立在对内存管理策略理解的基础之上。内容太多,简单的写写。

Agenda是: JVM内存划分 ->垃圾回收算法->内存分配策略->JVM垃圾收集器分类

JVM内存划分

1.方法区:存放Class定义,常量,全局变量
2.堆:存放对象实例
3.栈:(线程私有)对正在运行方法指令,变量值,实例引用进行压栈
4.PC计数器:(线程私有)记录当前指令位置
5.本地方法区:(线程私有)native code占用的内存。

堆中大量的实例死去以后,需要进行垃圾回收。否则就out of memory.方法区里面也需要进行垃圾回收,尤其是osgi和jsp的应用。大量的class动态生成,也会导致方法区out of memory.

满足下面条件,方法区的class定义所占内存将被回收

  1. class所有的实例均被回收。
  2. class的classloader被回收。
  3. class没有再被引用,以免使用reflect被初始化。

JVM启动参数 -Xnoclassgc 表示不对方法区进行垃圾回收。请谨慎使用。方法区垃圾回收到此结束。

后面所有的讨论都是关于堆中的垃圾回收。

回收算法

简单的说,如果一个实例没有再被使用,则可以当作垃圾被回收。如何判断实例是否被引用?通过根搜索,从GC roots开始,如果能找到实例,则实例还在被使用,如果找不到,则实例就已经死去。

GC roots可以是:

  • 栈中reference
  • 方法区中的reference

Java中对reference又分4类:

  • 强引用,不能回收
  • 软引用,第一次GC发生时,不回收,第二次回收
  • 弱引用,回收
  • 虚引用,回收 (虚引用我们接触不到,它是JVM用于接收垃圾回收后发送事件)。

新生代与老生代

堆中实例又被分为新生代和老生代。简单的理解,新生代是生命周期短,朝生夕死的实例,GC发生时新生代的成活率不足10%。老生代是一旦生成,就很难死去的实例。它们的成活率能占到近2/3.

新生代向老生代转变的几个条件:

  1. 新生代超过N次GC都没被回收,将变为老生代。N可以通过JVM参数指定,-XX:MaxTenuringThreshold=N. Parallel收集器默认是15.
  2. 如果实例需要的内存大小超过M,则直接分配到老生代。 M可以通过JVM参数指定。-XX:PretenureSizeThreshold=M。
  3. 如果suvivor中 同一代的实例在占据了survivor区(稍后讲)的一半以上,则年龄大于等于此代的一同进入老生代。
  4. Minor GC时,Survivor无法容纳存活新生代,由老生代空间担保,新生代被挪入老生代。

回收算法大体3类

  1. 标记-清除  顾名思义,就是将还在用的实例进行标记,然后将没标记的内存全部释放掉。 缺点是这将导致不连续的内存碎片,使得后面无法进行大块内存分配,从而导致再次出发GC。 老生代收集器CMS使用的算法。碎片也是CMS收集器的巨大缺点。
  2. 复制    新生代所使用的算法。新生代的内存分成3块,Eden和2个survivor. 因为大部分新生代成活率不到10%,所以,使用复制算法,将存活的实例复制到其中一个空白的survivor上,然后释放eden和另一个survivor的内存。两个survivor交替使用。上次GC用你,下次GC用我。默认情况下,Eden的大小是一个survivor大小的8倍。两个survivor相等。所以一个survivor占新生代内存的10%。 使用-XX:SurvivorRatio=8来改变eden与survivor的比例。
  3. 标记-整理  老生代经常使用的算法。和清除不同,将标记存活的实例向前移动,使得它们在内存上是存放连续的。

堆内存分配策略与GC触发

堆的大小由下面参数决定。
-Xms 堆最小值, -Xmx 堆最大值。

堆的大小动态调整
-XX:MaxHeapFreeRatio=70 当堆剩余空间达到70%,堆将变为Xms最小值。
-XX:MinHeapFreeRatio=40 当堆剩余空间低于到40%,堆将变成Xmx最大值。

堆分新生代和老生代。
-Xmn 为新生代大小。也可以用-XX:NewRatio=2来分配New/Old的比例。 2为默认值。

新生代又划分Eden和2*survivor。
-XX:survivorRatio=8来规定Eden/survivor的比例。8为默认值。

实例首先尝试分配在新生代eden上。如果实例所占内存超出限制XX:PretenureSizeThreshold,则直接分配到老生代。新生代分配内存时,如果eden空间不足,则触发新生代的GC, minor GC。老生代分配内存时,如果空间不足,则触发老生代的GC, full GC。老生代的GC比新生代GC要慢很多倍。老生代GC频率也比新生代低。

新生代minor GC时,如果存活的空间survivor容纳不下,则需要用老生代空间担保。如果老生代也容纳不下,就需要老生代做一次Full GC。 JVM会计算以往minor GC时新生代晋升老生代的平均大小,如果平均大小大于老生代剩余空间,则有很大可能发生担保失败,所以在minor GC前,先触发一次Full GC. 如果小于,则查看是否允许担保失败,如果允许,就直接进行minor GC。不允许,则先Full GC,再minor GC。

-XX:+HandlePromotionFailure 是允许老生代担保失败的发生。每次minor GC前,都会检查老生代剩余空间。JVM会计算以往minor GC时新生代晋升老生代的平均大小。此参数用于当平均大小小于老生代剩余空间时。以往小于不代表这次也小于,风险还是存在。如果允许担保失败,则直接进行minor GC, minor GC失败后,再Full GC. 如果不允许担保失败,则必须先运行Full GC,再minor GC。

这样子新生代GC时,如果survivor无法容纳存活实例,则将部分复制到老生代担保中。

垃圾回收器

Serial : 新生代收集器,使用copy算法。特点是单线程,当GC运行时,stop the world,所有的用户线程都必须暂停,等GC完成。缺点是停顿时间太长。

ParNew: 新生代收集器,使用copy,特点是多线程,也是停止用户线程,GC以后再运行用户线程。

Parallel: 新生代收集器,使用copy,但它注重JVM的吞吐量(JVM运行用户线程时间/GC线程时间),在提高吞吐量上有非常好的性能。它提供了很多可控参数,帮助调节JVM的吞吐量和停顿时间。

Serial Old: 老生代收集器,使用标记整理算法,特点跟serial 一样。

Parallel Old:老生代收集器,使用标记整理,产生于JDK 1.6,和Parallel搭配。在之前,Parallel只能和Serial old搭配,总体性能不是特别理想,现在双P。

CMS(Concurrent Mark Sweep):老生代收集器,使用标记清除。它的特点是可以和用户线程并发,可以减小停顿时间,但牺牲了吞吐量。CMS不能和Parallel搭配,一半和ParNew搭配。CMS的并发特性导致它3大缺点,1)对CPU要求高,2)无法清除因并发产生的浮动垃圾,3)容易产生碎片,为了清理碎片,每几次CMS之后,可以使用参数控制是否进行空间压缩。由于CMS是并发的,CMS需要预留空间给用户线程,一半老生代空间达到68%,就启动CMS. CMS过程中一旦程序失败,则发生CMS error。然后将使用Serial old作为它的备选,重新收集。CMS三个参数:

  1. XX:CMSInitiatingOccupancyFaction  设置老年代空间使用多少后出发CMS垃圾收集。一般是68%
  2. XX:UseCMSCompactAtFullCollection 每次CMS Full GC以后,做一次碎片整理。
  3. XX:CMSFullGCsBeforeCompaction 规定在多少次CMS Full GC以后,做一次碎片整理。

G1,传说中的新收集器,可以指定停顿时间,更高的效率。

Serial 和 serial old适合Client端的JVM。
Server端常用的是Parallel + Parallel Old, ParNew + CMS.
Parallel + Parallel Old 的吞吐量高
ParNew + CMS可减小停顿时间。

使用哪一个收集器,可以在JVM启动时用VM参数来指定。具体参考官方JVM options。

完。

转载于:https://my.oschina.net/xpbug/blog/55010

JVM内存分配与垃圾回收浅析相关推荐

  1. JVM内存分配与垃圾回收

        其实已经有很多大牛在这方面做了很好的介绍,我在这篇文章里讲下我自己的一些理解,受限于我的认知水平,可能不一定正确,请自我甄别. JVM的GC自动垃圾回收器是JAVA的一大特色,垃圾回收器要解决 ...

  2. 详解JVM内存管理与垃圾回收机制2 - 何为垃圾

    随着编程语言的发展,GC的功能不断增强,性能也不断提高,作为语言背后的无名英雄,GC离我们的工作似乎越来越远.作为Java程序员,对这一点也许会有更深的体会,我们不需要了解太多与GC相关的知识,就能很 ...

  3. 详解JVM内存管理与垃圾回收机制5 - Java中的4种引用类型

    在Java语言中,除了基础数据类型的变量以外,其他的都是引用类型,指向各种不同的对象.在前文我们也已经知道,Java中的引用可以是认为对指针的封装,这个指针中存储的值代表的是另外一块内存的起始地址(对 ...

  4. JVM内存结构和垃圾回收机制

    目录 JVM内存结构 JVM内存分配机制 对象回收判断机制 引用计数法 可达性分析算法 垃圾回收算法 标记-复制 标记-清除 标记-整理 垃圾回收器 serial(-XX:+UseSerialGC - ...

  5. JavaScript内存分配及垃圾回收机制

    JavaScript内存分配及垃圾回收机制 简介 像C语言这样的高级语言一般都有底层的内存管理接口,比如 malloc()和free().另一方面,JavaScript创建变量(对象,字符串等)时分配 ...

  6. jvm内存模型与垃圾回收

    *JVM历史JIT编译(just-in-time compilation)狭义来说是当某段代码即将第一次被执行时进行编译,因而叫"即时编译" 互联网-js人工智能-python微服 ...

  7. JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)

    转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...

  8. JVM内存模型与垃圾回收GC

    Java开发有个很基础的问题,虽然我们平时接触的不多,但是了解它却成为Java开发的必备基础--这就是JVM.在C++中我们需要手动申请内存然后释放内存,否则就会出现对象已经不再使用内存却仍被占用的情 ...

  9. 程序猿的日常——JVM内存模型与垃圾回收

    Java开发有个很基础的问题,虽然我们平时接触的不多,但是了解它却成为Java开发的必备基础--这就是JVM.在C++中我们需要手动申请内存然后释放内存,否则就会出现对象已经不再使用内存却仍被占用的情 ...

最新文章

  1. VS2010中如何更改项目名称【转】
  2. webservice 基本要点
  3. angular是MVC模式还是MVVM架构模式
  4. 用LVM快照创建虚拟机
  5. ARM体系的异常中断
  6. unrecognized selector sent to class 0x235e7ec
  7. vue-element-admin——登录页面添加自定义背景
  8. 计算机里的本地安全策略在哪找,本地安全策略哪里去了?
  9. css html文字淡入淡出,Css淡入淡出
  10. 剪切的东西不见了怎么找回来?
  11. 【转载】如何自己DIY组装一台台式电脑
  12. Laplace变换基础
  13. 数字金字塔(保证两位数的数字也能排好)
  14. 【TokenInsight 评级报告】NEM:评级BBB,展望稳定
  15. vue使用高德地图搜索地址添加标记marker,定位,拖拽选址功能
  16. Algebraic Teamwork
  17. 小地图的制作,游戏中的导航仪,minimap制作(继续我们的仙剑demo)
  18. 如何搭建一个好的知识库管理系统?
  19. elastic:Another Kibana instance appears to be migrating the index
  20. 交换机常用命令(1)

热门文章

  1. uniapp中动态修改导航栏标题
  2. 微信小程序/uni-app 封装请求
  3. 对学校公开课信息网站一次渗透测试
  4. HDU 3625 Examining the Rooms【第一类斯特灵数】
  5. Promise对象和async函数
  6. 团队编程项目作业5-小组评分
  7. onethink的熟悉
  8. html页面button样式
  9. 基于通用权限管理系统实现的单点登录
  10. IE6-IE9兼容性问题列表及解决办法_补遗漏之一:button的type默认值改变为submit了。