JVM自动内存管理机制

jdk1.6   sun hotspot

运行时数据区域

程序计数器

  1. 一块较小的内存空间,当前线程所执行的字节码的行号指示器。
  2. 线程私有的内存
  3. 可以认为是存储当前线程执行的字节码指令地址,配合cpu调度
  4. 唯一一个在jvm规范中没有规定任何oom情况的区域

Jvm Stacks

  1. 线程私有,生命周期同线程
  2. Java方法执行的内存模型,每一个方法被执行的时候都会创建一个栈帧
  3. 栈帧:存储局部变量表、操作栈、动态链接、方法出口等信息
  4. 每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程
  5. 局部变量表
  6. 这个区域,jvm规范中规定了两种异常:线程请求的栈深度超过虚拟机所允许的深度:stackoverflowError  虚拟机栈如果可以动态扩展,当扩展时无法申请到足够的内存 oom

 本地方法栈

       sun hotspot 中 本地方法栈和jvm栈合二为一

 java heap (堆)

  1. 一般堆是虚拟机所管理的内存中最大的一块
  2. Java堆是所有线程共享的一块区域,在虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例。
  3. Java堆可以细分为:新生代和老年代;其中新生代又可细分为:Eden/From Survivor/To Survivor
  4. TLAB
  5. 堆的这些划分目的是为了更好的回收内存,更快的分配内存
  6. 设置堆大小的参数 –Xmx(最大空间)/-Xms(最小空间)/-Xmn(新生代空间)
  7. 存在异常 oom

方法区

  1. 线程共享的内存区域
  2. 主要存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码
  3. 永久代
  4. 存在异常oom

运行时常量池

  1. 方法区的一部分
  2. 用于存放编译期生成的各种字面量和符号引用
  3. 存在异常oom

直接内存

 

对象访问

       句柄访问方式

       指针访问方式

       sun hotspot 采用指针访问方式

 实战:oom

 

垃圾收集器与内存分配策略

对象存活

       引用计数算法

                宏观定义:jvm 会为对象维护一个引用计数,gc时根据对象的引用计数来判断是否回收该对象,该算法存在对象间互相引用,致使对象的计数大于0的现象,gc无法判           断对象是否可以被回收,这也是Java虚拟机未采用该算法的主要原因

       根搜索算法:

              Java中GC Roots对象

                     虚拟机栈中引用的对象

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

                     方法区中常量引用的对象

                     本地方法中JNI引用的对象

          概念:

                     从上叙GC Roots对象开始向下搜索,当一个对象到GCRoots没有任何引用链相连时,则此对象不可用。

       引用的概念

                     强引用 软引用 弱引用 虚引用

              回收方法区

                     主要回收两部分内容:废弃常量和无用的类

                     废弃常量:没有任何引用的常量

                     无用的类:所有实例都被回收;加载该类的ClassLoader已经被回收

                                          该类对应的class对象没有在任何地方被引用

                     Jvm控制参数:-Xnoclassgc    设置 

      -verbose:class   –XX:+TraceClassLoading

      –XX:+TraceClassUnLoading   查看

垃圾收集算法

       标记-清除算法

              概念:标记所有需要回收的对象,在标记完成后统一回收掉所有标记的对象,后续算法都是在弥补该算法的缺点而衍生出来的不同方式

              缺点:

                     效率问题:标记和清除的效率都不高

                     空间问题:标记清除后会产生大量的内存碎片

       复制算法

              概念:将可用内存按照容量划分为大小相等的两块,每次只使用其中的一块。当被使用的这块内存用完了,就将存活的对象复制到另外一块上面,然后把先前的那块内存已       使用的空间一次性清理掉。

              目前jvm的做法是:将堆内存新生代和老年代,其中新生代分为 eden和两块survivor空间,比例8:2;新生代采用的就是复制算法

       标记整理算法

              概念:标记阶段同标记-清除算法,整理阶段:该算法是先让存活对象向一端移动,然后直接清理掉端边界以外的内存

      

  分代收集算法

         概念:根据对象的存活周期的不同将内存划分为几块。例如jvm 堆分为新生代和老年代,根据各个代的特点采用以上具体的收集算法。

      

垃圾收集器gc  hotspot  jvm 1.6u22

 

新生代

  serial收集器

  ParNew收集器

         摘要:Serial收集器的多线程版本

         -XX:+UseConcMarkSweepGC的默认新生代gc

         -XX:+UseParNewGC 强制指定新生代gc 为 ParNew GC

  Parallel Scavenge收集器

         关注点不同于其他gc,其关注点是:达到一个可控制的吞吐量

         -XX:MaxGCPauseMillis 最大垃圾收集停顿时间

         -XX:GCTimeRatio 吞吐量大小

         -XX:+UseAdaptiveSizePolicy  开启该设置可以不用关注其他一些gc策略细节参数比如:-Xmn,-XX:SurvivorRatio,-XX:PretenureSizeThreshold等

 

老年代

  Serial Old GC

         摘要:Serial GC 的老年代版本,单线程GC,采用 标记-整理算法

  Parallel Old GC

         摘要:该GC使用多线程和“标记-整理”,JDK1.6中才开始提供

  CMS GC (Concurrent Mark Sweep)

         摘要:一种为获取最短停顿时间为目标的收集器;采用 标记-清除

         “浮动垃圾”:CMS清理阶段,用户线程产生的新的垃圾,这些垃圾在本次GC不会被清理掉

         默认情况下:CMS在老年代使用了68%的空间后就会被激活,相应参数设置

                              -XX:+CMSInitiatingOccupancyFraction

         缺点:a.CMS 对CPU资源非常敏感 CMS默认启动的回收线程数:(CPU数量+3)/4

                  b.CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一个Full GC的产生。

                  c.CMS基于“标记-清除”算法实现,会产生大量的空间碎片

                       -XX:+UseCMSCompactAtFullCollection开关参数:在fullGC后 进行一次对片整理

                       -XX:CMSFullGCsBeforeCompaction  设置在执行多少次不压缩的GC后,跟着进行一次压缩。

 

G1

  G1收集器

         摘要:基于“标记-整理”算法实现,非常精确地控制停顿,jdk1.6u14开始有测试版本

         G1 将整个Java堆划分为多个固定的独立区域,并且跟踪这些区域种的垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域

 

 

内存分配和回收策略

       对象优先在Eden分配

       大对象直接进入老年代

       长期存活的对象将进入老年代

       动态对象年龄判断

              如果在survivor空间种相同年龄所有对象大小的总和大于survivor空间的一半,年龄大于或等于该年龄的对象将会直接进入老年代

       空间分配担保

      

posted @ 2018-07-16 15:40  道林格雷  阅读(247)  评论(0编辑  收藏  举报