jvm
jvm
基于hotspot虚拟机,C++ 可以进行源码编译jdk源码, 了解GC,内部原理,运行时参数等等。。。
类加载机制
加载:根据类名将二进制数据加载到内存
连接
验证:文件格式 字节码 元数据
准备:设置初始值;
解析:字段 方法
初始化 init方法 和构造方法
使用
卸载
双亲委派机制: bootstrapCL -> extCL-> sysCL->userCL
字节码文件结构:
字节码指令
javap -verbose xx(class)
加载和存储指令:iload 将局部变量加载到操作数栈 istore iconst
运算指令:iadd isub
类型转换指令:l2i i2l
对象创建和访问指令:new newarray
操作数栈管理指令:pop pop2 dup dup2
方法调用和返回指令:invokevirtual invokeinterface invokestatic
异常处理指令:异常表来完成
同步指令:monitorenter monitorexit
运行时数据区
程序计数器 :线程私有,当前线程所执行字节码的行号指示器 没有OOM的区域
java虚拟机栈 :线程私有,方法运行时创建栈帧, 包含 局部变量表,操作数栈,动态链接,方法出口 OOM 和 StackOverFlow
本地方法栈 : 线程私有 native方法 OOM 和stackOverFlow
堆: 线程共享 实例对象和数组 都在堆上分配 GC的主要部分
方法区: 类信息 常量 静态变量 , 常量池(包含类的符号引用)是方法区的一部分
直接内存: 零拷贝使用的数据区, 使用DirectByteBuffer对象作为内存的引用, 避免java堆和native堆得复制
对象创建过程:
new 检查类是否加载;
分配内存
根据JAVA堆是否规整决定使用:指针碰撞(空间连续 Serial ParNew算法),空闲列表(不连续 CMS算法);
CAS保证更新的原子性 ; TLAB(本地线程分配缓冲)-XX:+/-UseTLAB
对象内存布局:
对象头:
mark word:
hashcode,GC分代年龄,锁标志位,线程持有的锁,偏向线程id
类型指针:通过这个指针来确定是哪个类的实例
实例数据:data
对齐填充:padding
对象访问定位:
句柄:分为句柄池 和实例池,
直接指针: 对象类型和对象实例在一起, 快 hotspot默认
对象存活:
引用计数法: 相互引用 计数器;
可达性分析: GCroot:虚拟机栈中的本地变量表;方法区中静态变量,常量; 本地方法栈:JNI引用的对象
引用分类:
强引用:Object obj=new Object() 不会回收
弱引用:内存不足前回收,softReference
软引用:生存到下一次GC之前,不论内存是否足够,都回收 weakReference threadLocal
虚引用:唯一作用是被回收时收到一个系统通知 管理堆外内存 和queue有关
GC算法
标记清除: 效率低,内存碎片
复制: 90%对象 朝生夕死 8:1:1
空间分配担保 90%可以用,回收之后占10% 但是偶尔10% 不够,则利用老年代空间进行保存。
标记整理:老年代算法 对象存活率高,复制不好效率低;
分代收集: 不同年代选择不同的算法 存活率低 -> 复制算法;高 ->标记清除、标记整理
逃逸分析(只要是多个线程共享的对象就是逃逸对象)
栈上分配(栈上分配就是为了减少垃圾回收的次数):
对象和变量范围出方法的范围;
没有逃逸的对象 进行栈上分配
需要开启配置;
GC回收器
serial gc线程单线程
parNew Gc线程多线程
parallel Scavenge 默认新生代收集器 复制 多线程
吞吐量高: 用户时间/总时间
stop world
CMS
G1 内存模型
对象分配策略:
优先edon区
大对象直接进入老年代
长期存活进入老年代
常见JVM参数
-Xmx512m
-Xms512m
-Xmn128m
-XX:PermSize=96m
-XX:MaxPermSize=96m
-Xnoclassgc
-XX:+UseParNewGc
-XX:+UseConcMarkSweepGc
-XX:+CMSInitiatingOccupancyFraction=85
分析工具
进程:jps -l
统计:jstat -gc [pid] 250 10 250ms 10次
配置:jinfo -flags [pid]
jmap: jmap -dump:live,format=b,file=a.txt [pid]
jstack: 堆栈 线程
jconsole、virtual VM: 可视化