JVM(一)--你要从这几个方面开始
JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
Java语言的可移植性正是建立在Java虚拟机的基础上。任何平台只要装有针对于该平台的Java虚拟机,字节码文件(.class)就可以在该平台上运行。这就是“一次编译,多次运行”。
/ JVM内存结构 /
可以看出JVM分两个子系统和两个组件
子系统:类加载器 + 执行引擎
组件:运行时数据区 + 本地库接口
这三个完全是三个不同的概念
/ 运行时数据区 /
存储类的信息[创建的时间/元数据的信息]、常量池、静态变量、即时编译器编译之后的代码
线程共享,但数据非安全
如果方法区域中的内存无法满足分配请求,Java虚拟机将抛出OutOfMemoryError。
用来存放对象/数组
线程共享,会被多个线程共享,数据非安全
如果计算需要的堆超过了自动存储管理系统所能提供的堆,Java虚拟机将抛出OutOfMemoryError.
线程私有
可用于实现Java虚拟机指令集的解释器。是我们的代码运行空间。我们编写的每一个方法都会放到 栈 里面运行。
如果线程中的计算需要比允许的更大的本地方法堆栈,则Java虚拟机将抛出StackOverflowError。
如果可以动态扩展本机方法堆栈并尝试扩展本机方法堆栈,但可用内存不足,或者如果可用内存不足,无法为新线程创建初始本机方法堆栈,则Java虚拟机将抛出OutOfMemoryError。
Java虚拟机可以同时支持多个执行线程。
每个Java虚拟机线程都有自己的pc(程序计数器)寄存器。
在任何时候,每个Java虚拟机线程都在执行单个方法的代码,即该线程的当前方法。
如果线程当前执行的方法是本机的,则Java虚拟机的pc寄存器的值是未定义的。
Jdk1.7 前 方法区就是永久代 运行时常量池在 永久代
Jdk1.7 时 方法区就是永久代 运行时常量池在 堆
Jdk1.8 时 方法区就是元空间 运行时常量池在 堆
2、元空间参数使用
每个加载器有专门的存储空间。
不会单独回收某个类。
元空间里的对象的位置是固定的。
如果发现某个加载器不再存货了,会把相关的空间整个回收。
引用计数器:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题;
可达性分析:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。
标记-复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。
标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
绝大多数的对象都被回收-->一般对象都是朝生夕死的
下面是对朝生夕死的解释:GC日志
UnderStanding GC G1 Logs https://blogs.oracle.com/poonam/understanding-g1-gc-logs
2.从Young Old 分
3.从串行、并行、并发分
串行收集器
-->Serial、Serial Old
适用于内存较小的嵌入式设备,只能有一个垃圾回收线程执行,用户线程暂停
并行收集器(吞吐量优先)
-->ParNew、Parallel Scanvenge、Parallel Old
适用于科学计算、后台处理等弱交互场
并发收集器(停顿时间优先)
-->CMS、G1
适用于对时间有要求的场景,如web,用户线程和垃圾收集线程同时执行
4.并行 & 并发
并行(Concurrent):Two queues one coffee machine.
并发(Parallel): Two queues two coffee machines.
————Jeo Armstrong
CMS 是以牺牲吞吐量为代价来获得最短停顿时间的垃圾回收器,非常适用 B/S 系统。
在启动JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用CMS 垃圾回收器。
G1是一种兼顾吞吐量和停顿时间的GC 实现,是 JDK 9 以后的默认 GC 选项。
Garbage first 垃圾收集器是目前垃圾收集器理论发展的前沿成果,相比与CMS 收集器,G1 收集器两个突出的改进是:
一个类加载器,自己不会先加载,而是先在找自己的父类加载
如果父类加载器还存在父类加载器,则进一步是向上委托
如果父类加载器可以完成类加载任务,就成功返回,
如果父类加载器无法完成任务,子类加载器才会尝试自己去加载
这就是双亲委派原则,这就保证了只加载一次
JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,
其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。
jconsole:用于对 JVM 中的内存、线程和类等进行监控;
jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、gc变化等。
-Xms2g:初始化堆大小为 2g;
-Xmx2g:堆最大内存为 2g;
-XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;
-XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;
-XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
-XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
-XX:+PrintGC:开启打印 gc 信息;
-XX:+PrintGCDetails:打印 gc 详细信息。