zoukankan      html  css  js  c++  java
  • JVM总结+个人整理补充--转

    转自 http://blog.csdn.net/Luomingku_1109

    JVM是一种规范

    Java源文件 --> 编译器 --> 字节码文件

    字节码文件 --> JVM(解释器) --> 机器码

    Hotspot JVM 后台运行系统线程主要有下面几个

    VM Thread,等待JVM到达安全点操作出现

    • stop-the-world 垃圾回收
    • 线程栈dump
    • 线程暂停
    • 线程偏向锁(biased locking) 解除

    周期性任务线程

    • 定时器事件(中断),调度周期性操作

    GC线程

    • 支持JVM中不同的垃圾回收活动

    编译器线程

    • 在运行时将字节码动态编译成本地机器码

    信号分发线程

    • 接收发送到JVM的信号并调用适当的JVM方法处理

    • 程序计数器PC(私有),线程执行字节码的行号指示器
    • 虚拟机栈(私有),java方法执行的内存模型,每一个方法会创建一个栈帧,随着方法的调用和执行栈帧会入栈和出栈
    • 本地方法区(私有),为Native方法服务
    • (共享),Runtime的数据,创建的对象和数组都保存在Java堆内存中
    • 方法区/永久代(共享),存储JVM加载的类信息、常量、静态变量,即时编译器编译后的代码
    • 永久代的内存回收针对常量池的回收和类型卸载,收益很小
    • Runtime Constant Pool,运行时常量池,常量池,用来存放编译器生成的字面量和符号引用,类加载后放到方法区运行时常量池

    JVM运行时内存

    Eden区(伊甸园)

    • Java新对象的出生地(若新对象内存占用大,直接分配到老年代)
    • 当Eden区内存不够时,会触发MinorGC(新生代GC),堆新生代进行垃圾回收

    SurvivorFrom

    • 从上次GC中活下来的对象

    SurvivorTo

    • 上一次MinorGC在Eden和SurvivorFrom的幸存者

    MinorGC的过程采用复制算法(复制->清空->互换)

    • 把Eden和SurvivorFrom区域中存活的对象复制到SurvivorTo区域
    • 如果有对象年龄到达了老年标准(默认15),会送到老年代
    • 所有对象年龄+1(通过一个Age计数器)

    清空Eden、survivorFrom

    SurvivorFrom和SurvivorTo互换

    • 可以保证对象内存的连续化

    老年代

    • 存放应用程序中生命周期长的内存对象
    • 比较稳定,MajorGC不会频繁执行
    • 在执行MajorGC前一般先进行一次MinorGC,使得新生代进入老年代,导致空间不够用触发
    • MajorGC采用标记清除算法
    • 当老年代也满了,会抛出OOM(Out Of Memory)异常

    永久代

    • 内存的永久保存区域,存放Class和Meta(元数据)
    • GC不会在主程序运行期永久区域进行清理,导致永久代随着Class的增多而胀满,抛出OOM

    JAVA8与元数据

    • 在JAVA8中,永久代被移除,被一个称为"元数据区"的区域所取代
    • 元空间与永久代之间的区别:元空间不在虚拟机中,使用本地内存
    • 类的元数据放入native本地内存,字符串池和类的静态变量放入java堆中

    垃圾回收算法

    引用计数法

    • 虚拟机并不是通过引用计数算法判断对象是否存活
    • 引用计数法,给对象添加一个引用计数器,有一个地方引用它,计数器+1
    • 当引用失效,计数器-1,任何时刻,计数器为0的对象不可能再被使用

    可达性分析算法

    • 为了解决引用计数法的循环引用问题
    • 从称为“GC Roots”的对象作为起始点,从节点开始向下探索,探索所走过的路径称为引用链(Reference Chain)
    • 若在"GC Roots"和一个对象之间没有可达路径,称该对象不可达

    标记清除算法(Mark-Sweep)

    • 先标记再清除
    • 效率低,而且会产生大量不连续的碎片,后面分配对象内存可能会无法找到足够大的连续内存

    复制算法(Copying)

    • 将内存划分为大小相等的两块,每次只使用其中一块
    • 当一块内存用完,就将存活的对象复制到另一块上,清理已经使用的空间
    • 不用考虑内存碎片的复杂情况,代价是内存缩小为原来的一半
    • 现代商业虚拟机都采用这种收集算法回收新生代

    标记整理算法(Mark-Compact)

    • 先标记,然后把对象移动到内存的一端,然后清除端边界外的对象

    分代收集算法

    • 大部分JVM采用的方法,核心思想,根据对象存活的声明周期将内存划分为不同域
    • GC划为Tenured/Old Generation 和 Young Generation

    新生代与复制算法

    • 大部分JVM的GC对新生代采取Copying算法
    • Minor GC时,将两块空间中还活着的对象复制到另一块Survivor空间

    老年代与标记复制算法

    • 永久代存储Class,常量,方法描述
    • 新对象主要在Eden,Survivor的From和To空间
    • 新生代的内存区域发生Minor GC时,存活对象移动到Survivor To空间,清理Eden和Survivor From空间
    • 如果Survivor Space满了,会放到老年代
    • 存活对象躲过一次GC,年龄+1,默认15岁会送到老年代

    JAVA四种引用类型

    强引用

    • 把一个对象赋给一个应用变量,处于可达状态,不可能被垃圾回收机制回收,Java内存泄漏的主要原因之一

    软引用

    • 使用SoftReference类实现,内存足够不会被回收,内存空间不足会被回收,用在对内存敏感的程序中

    弱引用

    • WeakReference类实现,比软引用生存期短,只要GC运行,就会回收该对象的内存

    虚引用

    • 通过PhantomReference类实现,与引用队列联合使用,跟踪对象被垃圾回收的状态

    分区收集算法

    • 分区算法将整个堆空间划分为连续的不同小区间,每个小区间独立使用,可以控制一次回收多少个小区间
    • 每次合理回收若干个小区间(而不是整个堆),从而减少一次GC所产生的停顿

    垃圾收集器

    Serial(连续)垃圾收集器(单线程、复制算法)

    • 只会使用一个CPU或一条线程去完成垃圾收集工作,并在垃圾收集的同时,暂停其他所有的工作线程
    • 简单高效,对于单个CPU来说,没有线程交互的开销,可以获得单线程的最高垃圾收集效率、
    • java虚拟机运行在Client模式下默认的新生代垃圾收集器

    ParNew垃圾收集器(Serial+多线程)

    • Serial收集器的多线程版本
    • ParNew垃圾收集器在垃圾收集过程中同样暂停所有其他工作线程
    • ParNew默认开启和CPU数目相同的线程数,可以通过:-XX:ParallelGCThreads,限制垃圾收集器的线程数
    • Server模式下新生代的默认垃圾收集器

    Parallel Scavenge收集器(多线程复制算法、高效)

    • 新生代垃圾收集器,使用复制算法,多线程垃圾收集器
    • 程序达到一个可控制的吞吐量(Throughput)
    • 吞吐量 = 运行时间/(运行时间+垃圾收集时间)
    • 高吞吐量可以高效率利用CPU
    • 自适应调节策略也是ParallelScavenge收集器与ParNew收集器的一个重要区别

    Serial Old收集器(单线程标记整理算法)

    • Serial收集器的老年代
    • JDK1.5前与新生代的Parallel Scavenge收集器搭配使用
    • 作为老年代中使用CMS收集器的后备垃圾收集方案

    新生代Serial与老年代Serial Old搭配垃圾收集过程

     新生代Parallel Scavenge收集器与ParNew收集器都是多线程的收集器,都使用复制算法,都暂停工作线程

     新生代Parallel Scavenge/ParNew收集器与老年代Serial Old搭配垃圾收集过程图

     

     Parallel Old收集器(多线程标记整理算法)

    • JDK1.6开始提供
    • ParaellScavenge收集器只能搭配老年代的Serial Old收集器,Paralle Old 为老年代同样提供吞吐量优先的垃圾收集器
    • 若系统对吞吐量要求比较高,考虑新生代Parallel Scavenge和年老代Parallel Old收集器的搭配策略

    新生代Parallel Scavenge和老年代Parallel Old收集器搭配运行过程

     CMS收集器(多线程标记清除算法)

    • Concurrent mark sweep 收集器是一种老年代垃圾收集器
    • 主要目标是获取最短垃回收停顿时间,和其他老年代使用标记-整理算法不同,使用多线程的标记-清除算法

    CMS的工作过程

    • 初始标记,标记一下 GC Roots能直接关联的对象,速度很快,仍然需要暂停所有的工作线程
    • 并发标记,进行GC Roots 跟踪过程,和用户线程一起工作,不需要暂停工作线程
    • 重新标记,用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍需要暂停所有的工作线程
    • 并发清除,清除GC Roots不可达对象,和用户线程一起工作,不需要暂停工作线程,耗时最长的并发标记和并发清除过程中,垃圾收集线程可以和用户一起并发工作
    • 总体上看,CMS收集器的内存回收和用户线程是一起并发执行的

     G1收集器

    Garbage first垃圾收集器是目前垃圾收集器理论发展的前沿成果

    • 基于标记-整理算法,不产生内存碎片
    • 精确控制停顿时间,不牺牲吞吐量前提下,实现低停顿垃圾回收
    • G1收集器避免全区域垃圾收集,把堆内存划分为大小固定的几个独立区域,跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域。区域划分和优先级区域回收机制,确保G1收集器可以在有限时间内获得最高的垃圾收集效率
    论读书
    睁开眼,书在面前
    闭上眼,书在心里
  • 相关阅读:
    54. 八皇后问题[eight queens puzzle]
    53. 特殊的O(n)时间排序[sort ages with hashtable]
    52. 不用+、-、×、÷做加法[add two numbers without arithmetic]
    C++基础知识面试精选100题系列(11-20题)[C++ basics]
    C++基础知识面试精选100题系列(1-10题)[C++ basics]
    洛谷 P1479 宿舍里的故事之五子棋
    洛谷 P2084 进制转换
    codevs 1700 施工方案第二季
    POJ 3278 Catch That Cow(求助大佬)
    POJ 2251 Dungeon Master
  • 原文地址:https://www.cnblogs.com/YC-L/p/13615530.html
Copyright © 2011-2022 走看看