jvm总结
类加载过程
加载 验证 准备 解析 初始化
1.加载:在硬盘上查找并通过io读入字节码文件
2.验证:校验字节码文件的正确性
3.准备:给类的静态变量分配内存,并赋予默认值
4.解析:将符号引用替换为直接引用,该阶段会把一些静态方法(符号引用比如main()方法)替换为指向数据所存内存的指针或句柄。
5.初始化:对类的静态变量初始化为指定的值,执行静态代码块
类加载过程主要是通过类加载器来实现的,java里有如下几种类加载器
1.启动类加载器 加载 jre lib目录下的核心类库
2.扩展类加载器 加载jre lib目录下的ext扩展目录中jar
3.应用程序类加载器 加载classpath路径下的类包主要就是要加载你写的那些类
4.自定义加载器 负责加载用户自定义路径下的类包
双亲委派机制: 加载类是会先委托父加载器寻找目标类,找不到再委托上层父加载器加载,如果所有的父加载器都加载不到,则用自己的类加载器加载
JVM整体结构及内存模型
共享: 堆 ,方法区
私有:栈,本地方法栈,程序计数器
栈:局部变量表,操作数栈,动态链接,方法出口
动态链接 在程序运行期间完成的将符号引用替换为直接引用
逃逸分析
jvm运行模式有三种
1.解释模式:只使用解释器 ,执行一行jvm字节码就编译一行机器码
2.编译模式:只使用编译器,将所有jvm字节码一次编译为机器码,然后一次性执行所有机器码
3.混合模式:依然使用解释模式执行代码,但是对于一些“热点”代码,采用编译模式执行,jvm一般采用混合模式执行代码
对象逃逸分析:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中。
当确定方法结束这个对象是无效对象了,对于这样的对象我们其实可以将其分配的栈内存里,让其在方法结束时跟随栈内存一起被回收掉
jvm内存分配与回收
1.对象优先在eden区分配
2.大对象直接进入老年代(大对象就是需要大量连续内存空间的对象比如:字符串,数组)jvm参数 -xx:PretenureSizeThreshold可以设置大对象的大小这个参数只在Serial和praNew两个收集器下有效
3.长期存活的对象进入老年代
如果一个对象在eden出生并经过第一次minor gc后仍然能够用存活,并且被survivor容纳移到survivor空间中,将对象的年龄设为1,每熬过一次minorgc年龄+1,当年龄增加到15时会被晋升到老年代。
4.对象动态年龄判断
例如survivor区现在有一批对象 年龄为1+2+3+n,如果这批对象总和超过了survivor区的50%就会把年龄n及n以上的都放入老年代
5.minor gc后存活的对象survivor区放不下
6老年代空间分配担保机制
年期代每次minor gc前都会计算老年代的剩余可用空间
如果设置了-XX:-HandlePromotionFailure(jdk1.8默认设置)这个参数,就会看老年代的可用内存大小是否大于之前每次minor gc后进入老年代的对象的平均大小,如果小于或者那个参数没有设置的话会触发一次full gc。
7.eden与survivor区默认8:1:1
如何判断对象可以被回收
可达性分析算法
从gc roots根节点作为起点,从这些节点开始向下搜索,找到的都标记为非垃圾对象,其余未标记的对象都是垃圾对象
gc roots根节点:线程栈的本地变量,静态变量,本地方法栈的变量
finalize()方法最终判定对象是否存活
当对象没有覆盖finalize方法,对象直接被回收
如果对象覆盖了finalize方法,在方法里面重新与引用连上的任意一个对象建立关联,就可以不被回收。
如何判断一个类是无用的类
1.该类的所有实例都已经被回收
2.加载该类的classloader已经被回收
3.该类对应的class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
垃圾收集算法
1.标记清除算法
2.复制算法
3.标记整理算法
4.分代收集算法
垃圾收集器
1.serial收集器
单线程的,新生代采用复制算法,老年代采用标记整理算法
2.parnew收集器
多线程的,新生代采用复制算法,老年代采用标记整理算法
3.parallel scavenge收集器
类似parnew收集器 ,不同点在于他关注吞吐量(cpu中用于运行用户代码的时间和cpu总消耗时间的比值)提供了很多参数公用户选择合适停顿时间或最大吞吐量。新生代采用复制算法,老年代采用标记整理算法
4.cms收集器
垃圾收集线程和用户线程能够同时工作
过程分为四个步骤
1.初始标记 暂停所有的其他线程,记录gc roots直接能引用的对象
2.并发标记 同时开始gc和用户线程,记录可达对象
3.重新标记 为了修正并发标记期间因为用户程序继续运行而导致的标记产生的变动
4.并发清理: 开启用户线程,同时gc线程对为标记的区域做清扫
优点:并发收集,低停顿
缺点:
1对CPU资源敏感
2.无法处理浮动垃圾(在并发清理阶段又产生的垃圾,只能等到下一次gc再清理)
3.会存在上一次垃圾回收还没执行完,然后又垃圾回收又被触发的情况特别是在并发标记和并发清理阶段可能会出现,此时会stop the world,用serial old垃圾收集器来收集
它使用的是 标记-清除算法,当然通过-XX:+UseCMSCompactAtFullCollection 可以让jvm在标记清除后再做整理
5.G1收集器
G1将堆划分为多个大小相等的独立区域,jvm最多可以有2048个region,一个region大小等于堆大小除以2048,G1有专门分配大对象的region叫humongous区。
gc步骤
1.初始标记 暂停所有的其他线程,记录gc roots直接能引用的对象
2.并发标记 同时开启gc和用户线程,记录可达对象
3.最终标记:为了修正因并发标记期间因为用户线程产生的标记的变动
4.筛选回收 对各个region的回收价值和成本进行排序,根据用户所期望的gc停顿时间来指定回收计划
回收主要采用的是复制算法,将一个region中存活的对象复制到另一个region中
Mixed GC 老年代的堆占有率达到设定的值时触发,回收所有的Young和部分Old以及大对象区,把各个region中存活的对象拷贝到其他region里去,如果发现没有足够的空region能够承载拷贝对象就会触发一次Full GC
导出dump文件
jmap -dump:format=b,file=aaa.hprof 12345