1.java内存模型
主内存:JMM规定所有的变量存储在主内存,
工作内存:线程私有,存储方法参数与本地变量
2.java运行数据区
1.方法区 2.堆 3.本地方法栈、4.虚拟机栈、5.程序计数器
程序计数器:当前线程做执行的字节码的行号指示器,线程私有,供恢复线程执行使用。
虚拟机栈:
线程私有,java方法执行内存模型,一个方法对应一个栈帧,存储局部变量表、操作数栈、动态链接、方法出口
本地方法栈:执行native方法提供服务
堆:所有线程共享的内存区域,作用存储对象实例及数组。
方法区:线程共享内存区域,存储已被jvm加载的类信息、常量、静态变量、即时编译器编译后的代码
运行时常量池:用于存放编译期间生成的各种字面量和符号引用。
直接内存:NIO,使用native函数分配堆外内存,通过存储在堆中的directByteBuffer对象对这块内存的引用进行操作,避免堆内存和native内存来回复制数据
2.垃圾回收
1.对象已死的原则
引用计数法:为每一个对象添加一个引用计数器,每当有一个地方引用它,计数器加1,当引用失效时,减1.任何时刻计数器为0的对象就是不再使用的。缺点:无法解决对象之间互相循环引用
可达性分析算法:通过一系列可称之为"GC Roots"的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径叫做引用链。当一个对象到GC Roots没有可用的引用链,就是不可达时,该对象就是可回收的对象
可作为GC Roots的对象:虚拟机栈(栈帧中的本地变量表)中引用的对象、方法区类静态属性引用的对象、方法区常量引用的对象、本地方法栈JNI(native方法)引用的对象
引用类型:强引用、软引用、弱引用、虚引用
垃圾回收算法:
标记清除算法:1.标记所有被回收的对象2.统一回收 缺点:效率低、产生内存碎片
复制算法:将可用内存一分为二,每次使用其中1块,当内存用完时,将还存活对象复制到另一块内存上,然后对整个半区进行回收,缺点:浪费空间。
改进:分为较大的eden和两块较小的survivor空间 ,每次使用eden和其中一块survivor空间 8:1:1
标记整理算法:所有存活对象向一端移动,然后清理端以外的空间
分代收集算法:java堆分为老年代和新生代,新生代采用复制算法,老年代采用标记整理算法、标记清理算法。
hotspot算法实现
枚举根节点、安全点、安全区域
垃圾收集器:
serial:单线程收集器。stop the word
过程:
parNew:serial的多线程版本
parallel scavenge:复制算法,并行多线程收集器
关注点:达到可控吞吐量
吞吐量=运用用户代码时间/(运行用户代码时间+垃圾回收时间)
serial old:使用标记-整理,图示见serial
parallel old 搭配 parallel scavenge
CMS:获取最短回收停顿时间为目标,采用标记清除
1.初始标记(stop the word) 标记 gc roots能关联到的对象
2.并发标记 :进行 gc roots tracking3.重新标记(stop the word)修正并发标记 因用户程序继续运行导致标记产生变动的那一部分 4.并发清除
缺点:cpu敏感 、无法处理浮动垃圾 产生空间碎片
G1 Garbage-first
1.并发与并行 2.分代收集 3.空间整合 4.可预测停顿
将内存化为多个大小相等的region,跟踪每个region的垃圾堆积的价值大小,维护一个优先列表,根据允许的收集时间,优先回收价值大的region
1.初始标记 2.并发标记 3.最终标记 4.筛选回收
类加载机制:
jvm将class 二进制文件加载到内存,并对数据进行校验、解析和初始化,最终形成被jvm直接使用的java类型
什么情况下对类进行初始化:
1.new 实例化对象 、读取设置类的静态变量、调用类的静态方法
2.对类进行反射调用
3.父类还没有初始化
4.jvm启动,主类
5.MethodHandler
类加载过程
加载:通过全限定名获取二进制字节流,将字节流存储的静态结构转为方法区的运行时数据接口,在内存生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问接口
验证(保护机制):文件格式验证、元数据验证、字节码验证、符号引用验证
准备:分配内存,设置变量初始值
解析:将常量池中的符号引用变为直接引用
初始化:是所有类变量赋值动作和静态代码块合并而成
类加载器
双亲委派模型
启动类加载器(加载<java_home>\lib)
扩展加载器(加载<java_home>\lib\ext)
应用程序类加载器(系统类加载器)