jvm内存区域
- 程序计数器
当前线程执行字节码的行号,线程私有 - jvm 栈
线程私有,用来描述方法执行的,分为局部变量表、操作数栈、动态链接、方法出口存,局部变量表是放基本数据类型、String、和对象引用,方法执行会创建栈帧,方法嵌套层数过多会抛出StackOverFlow异常,如果jvm无法申请到足够的栈空间会报OOM - 堆
堆用来存储对象,是线程共享的区域,会发生OOM - 方法区
存储类信息,静态变量,常量
类加载
过程
加载-验证-准备-解析-初始化-使用-卸载
加载:
- 通过类的全名获取到二进制字节流(实际就是读文件)
- 将字节流转换成方法区中的动态数据结构
- 在堆中生成class对象
准备:
- 为类变量分配内存并设置初始值,但是实例变量不会。
- 设置初始值是数据类型对应的默认值,并非代码中值;
比如
public static int var = 1;
在初始阶段var的是0 不是1,赋值成1是在初始化阶段
初始化:
顺序:(父类静态变量>父类静态代码块)>(子类静态变量>子类静态代码块)>(父类变量>父类初始化块)>(父类构造方法)>(子类变量>子类初始化块)>(子类构造方法)
触发条件:
- new 对象
- 使用静态变量、静态方法
- 反射(classforName(xxx))
- 执行main方法
- 初始化子类会先初始化父类
类加载器
- Bootstrap Classloader 最顶层类加载器,加载java_home/lib路径下jar包和class文件
- Extention Classloader 拓展类加载器,加载java_hoe/lib/ext 路径下jar包和class文件
- Appication Classloader 应用类加载器
- 自定义类加载器 实现AppicationClassloader
- 两种方式
(1)遵守双亲委派模型:继承ClassLoader,重写findClass()方法。
(2)破坏双亲委派模型:继承ClassLoader,重写loadClass()方法。 通常我们推荐采用第一种方法自定义类加载器,最大程度上的遵守双亲委派模型。
- 步骤
(1)创建一个类继承ClassLoader抽象类
(2)重写findClass()方法
(3)在findClass()方法中调用defineClass()
双亲委派模型
类加载器收到类加载的请求后会先委托给父类去加载,所有请求都会传到Bootstrap ClassLoader,只有父类加载不到的才会自己执行。
好处:避免重复加载、安全
内存分配
- Edion
- 新创建的对象优先放到Edion
- 老年代
- 大对象直接进入老年代(好处是能减少Minor GC)
- Survivor中多次存活的对象进入老年代
- Minor GC后新生代存活的对象大于Survivor空间的一半 存储到老年代
垃圾回收
- Minor GC条件
当Edion不足以创建对象时 - Full GC
当Minor GC后需要进入到老年代对象大于老年代剩余空间
垃圾回收算法
- 引用计数器算法
- 标记清除算法
- 标记整理算法
- 复制算法
- 分代收集算法