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收集器可以在有限时间内获得最高的垃圾收集效率
论读书
睁开眼,书在面前 闭上眼,书在心里
睁开眼,书在面前 闭上眼,书在心里