内存模型
堆、栈、方法区、本地方法栈、程序计数器
栈:线程私有。局部变量表,操作栈,动态链接,方法出口,执行java方法
本地方法栈:线程私有。执行Native方法
程序计数器:线程私有。当前线程执行的字节码位置,为执行java方法服务
堆:内存中最大,线程共享。存放对象实例,分代管理。
方法区:线程共享。已被虚拟机加载的类信息,常量和静态变量。
类加载机制
类的加载:将编译好的class文件中的字节码读入到内存中,将其放在方法区并创建对应的class对象。
加载过程:加载(文件到内存)—链接(验证【文件内容验证:文件格式,元数据,字节码,符号引用验证,要符合规范】、准备【内存分配】、解析)—初始化(静态变量赋值)
类初始化的触发条件:
1. 创建类的实例
2. 访问类的静态方法或者静态变量
3. Class.forname()反射类
4. 子类被初始化
双亲委派加载机制
常用类加载器
GC
为什么要回收?
回收垃圾,释放内存
什么时候回收?
新生代内存慢时,会出发minorGC
收回哪些对象?
1. 引用计数法
2. 引用可达法
从GCRoots开始搜索—对象到GCRoots没有引用链相连,进行第一次标记—是否执行了finalize()
引用:无论通过哪种算法判断对象是否已死,判断都与引用有关。
1强引用:普遍存在的引用,只要引用存在,垃圾收集器就不会回收掉被引用的对象。
2.软引用:还有用但是非必须的对象。在系统将要发生内存溢出之前,会被列入回收范围。
场景:创建缓存的时候,创建的对象放在缓存中,当内存不足时,jvm就会回收早先创建好的对象,如图片,视频编辑器。
3.弱引用:生存到下一次垃圾回收之前。
4.虚引用:无法通过虚引用取得对象实例。
怎么回收?
分代垃圾回收机制。作用:优化GC性能。不同的对象处于不同的生命状态,及时对无用对象进行回收。
垃圾回收算法
1.标记清除算法
先标记需要回收的对象,完成后回收所有标记对象。
不足
1.效率问题。
2.空间问题。不连续内存碎片。
2.复制算法
相等的两块->每次使用一块->复制,清理
不足:内存缩小了一半。在对象存活率较高的时候进行较多的复制操作,效率变低。
3.标记-整理算法
在标记清除算法的基础上,让所有存活对象向一端移动,直接清楚掉端外之外的内存。
4.分代收集算法
新生代和老年代,根据各个年代的特点采用最合适的收集算法。新生代:大批对象死去,采用复制算法。
老年代中对象存活率较高,没有额外空间,使用标记-整理或标记清楚算法。
扩展:为什么需要两个survivor?
1. 如果没有两个,每一次GC,对象被送到老年代,老年代很快会被填满,会触发MajorGC,消耗时间
2. S区保证经历16次minorGC,还在新生区存活的对象,才送到老年代。
3. 减少碎片化。保留一个不用,用于复制另一个和eden中存活的对象。
内存分配策略
1.对象优先在eden分配。
2.大对象直接进入老年代。
3.长期存活的对象进入老年代。
4.空间分配担保。