虚拟机的结构
类的加载器、运行时数据区、执行引擎
其中运行时数据区分为堆、虚拟机栈、本地方法栈、方法区和程序计数器
方法区和堆是线程公有,其他的都是线程私有
运行时数据区
1.1程序计数器
程序计数器也是jvm的一块内存区域,不过它不会发生OutOfMemoryError的异常,消耗的内存很小,相比java栈堆,可以忽略掉。它的作用是通过计数器的值寻找执行指令的字节码,因为线程切换时需要恢复每一个线程当前的位置,所以每一个线程都有自己的程序计数器。
执行java方法时,存储执行指令的地址,执行本地方法,就会变成空(undefine)
1.2虚拟机栈
创建一个线程,虚拟机就会为线程创建一个虚拟机栈,虚拟机栈表示java方法执行的内存模型,调用一个方法就会生成一个栈帧用于存储本地变量表、操作栈等信息,方法执行完,会弹出相应的栈帧。
Java虚拟机中两种异常 栈的深度大于虚拟机所允许的最大深度,抛出StackOverflowError
虚拟机扩展栈时无法申请到足够空间,抛出out ofMemoryError
1.3本地方法栈
本地方法栈和虚拟机栈,虚拟机栈为虚拟机执行java方法服务,本地方法栈为虚拟机使用Native服务
1.4堆
Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建,此区域的唯一目的是存放对象实例,所有对象实例都在这里分配内存
Java堆分配内存的分配方法,指针碰撞,当需要分配一块内存是,指针移动,未分配内存的区域缩小,已分配的内存区域扩大
1.5方法区
是各个线程共享的内存区域,垃圾收集行为在方法区比较少出现,但方法区内存回收的主要目标是针对与常量池的回收和对类型的卸载。方法区无法满足内存分配需求会抛出OutOfMemoryError异常
运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用
对象
1.1对象的创建
虚拟机遇到new指令,首先去检查指令中的参数是否能在常量池中定位到一个类的符号引用,检查这个类是否被加载、解析和初始化,没有则进行类的加载过程。检查通过之后,为对象分配内存,如果内存是规整的,分配方法是指针碰撞。不规整,则使用“空闲列表”分配方式。
内存分配存在的问题是,对象创建是一个比较频繁的行为,在并发的情况下并不是线程安全的。两种解决方案:一是进行同步处理,即采用CAS加上失败重试的方式保证更新操作的原子性,二是每个线程在java堆中预先分配一小块内存,成为TLAB(本地线程分配缓冲)
空闲列表:虚拟机维护一个列表,表中记录了哪些内存块可用,从列表中找到一个内存块分配给对象,然后更新表上的记录
1.2对象的内存布局
对象在内存中的存储布局分为3个区域:对象头,实例数据、对齐填充
垃圾收集
垃圾收集算法
1.1、标记-清除算法
标记所有需要回收的对象,标记完成后,统一回收所有被标记的对象,
不足之处,标记和清除的效率不高,标记清除后会产生大量不连续的内存碎片
1.2、复制算法
为了解决效率问题,将内存分为大小相等的两块,每次使用一块,当这一块内存使用完了之后,将存活的对象放到另一块内存中,然后对原先那一半内存进行回收。实现简单,运行高效,不过代价是将内存缩小一半,代价过高。
1.3、标记-整理算法
是对标记清除算法的改进,进行标记好了之后,将存活的对象都向一边移动,然后直接清理掉端边界以外的内存
1.4、分代收集算法
商业虚拟机都采用“分代收集”算法,根据对象的存活周期将内存分为几块,一般是将java堆分成新生代和老年代,如果新生代有很少的存活对象,就用复制算法,老年代有很多存活对象,就用标记-清除或标记-整理算法
垃圾收集器
由于内存中的对象,是按存活周期存放在不同的内存块中的,所以,我们选择不同的算法来针对不同的内存块进行垃圾收集。从而,对于,不同的内存块,我们需要有不同的垃圾收集器。
新生代的垃圾收集器有:Serial收集器、ParNew收集器、Parallel Scavenge收集器
老年代的垃圾收集器有:Serial Old收集器、Parallel Old收集器、CMS收集器、G1收集器
1.1、Serial收集器/Serial Old收集器
串行,是单线程的,使用“复制”算法。当它工作时,必须暂停其它所有工作线程。特点:简单而高效。一般用于Client模式的JVM中
1.2、ParNew收集器
ParNew收集器,是Serial收集器的多线程版。是运行在Server模式下的虚拟机中首选的新生代收集器。除了Serial收集器外,目前只有它能与CMS收集器配合工作。
1.3、Parallel Scavenge收集器
吞吐量优先收集器,吞吐量=程序运行时间/(JVM执行回收时间+程序运行时间),是server模式JVM的默认配置
1.4、Parallel Old收集器
老年带client模式下默认的收集器,单线程执行,是CMS收集器失败后的备用收集器
1.4、CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,使用“标记-清除”算法。
回收线程数=(CPU核心数+3)/4
CMS收集器分4个步骤进行垃圾收集工作:
1、初始标记 2、并发标记 3、重新标记 4、并发清除
其中“初始标记”、“重新标记”是需要暂停其它所有工作线程的。
1.5、G1收集器
G1(Garbage First)收集器,基于“标记-整理”算法,可以非常精确地控制停顿。