文章目录
1. 子类和父类执行顺序
- 类加载(如果没有初始化类加载,则执行)
- 从字节码层面看:
- 类对象的初始化:类的构造方法(收集静态变量+静态代码块)
- 实例对象的初始化实例的构造方法(收集成员变量+实例代码块+Java层面的构造方法)
- 从字节码层面看执行顺序
- 父类的初始化:父类的构造该方法
- 子类的初始化:子类的构造该方法
- 父类的实例对象的构造方法:父类的实例对象构造方法(收集父类的成员变量,实例代码块,Java的构造方法)
- 子类的实例对象的构造方法:子类的实例对象构造方法
2.内存泄漏
- 内存泄漏:内存中,随着进程的运行时间越来越长,存放的无用的数据(变量/常量值,对象,类型)越来越多。可用内存空间越来越少。
- 内存泄漏的结果:进程一直运行,有用户一直使用系统,随着时间的越来越长,最终一定会出现某个内存区域出现空间不足的问题(OOM)
- 解决问题:
- 程序代码优化:如设置超时时间,超过了指定时长,定时清理长期不用的用户。(可以使用一些JVM的检测工具)
- 临时解决方案:有时候有老旧的大型项目,不太好优化(即使使用内存泄漏的检测工具,也不好定位)万能重启大法:隔一定的时间,重启java进程;如果隔的时间觉得太短,加内存。(如果系统内存不满足java进程所需要的内存,要加大系统内存)
- 内存泄漏,随着使用时间越来越长,最终一定会出现OOM,但是OOM不一定是内存泄漏引起的。
3. 垃圾回收
- Garbage Collection(GC),java 进程在启动后会创建垃圾回收线程,来堆内存中无用的对象进行回收。
- 什么是垃圾?
- 无用的对象(堆),常量(常量池),类型(方法区的类信息)
- 关于垃圾回收:
- Java进程启动——创建gc线程(垃圾回收器——回收——垃圾)
- 垃圾回收器:
- 基于垃圾回收算法来执行回收工作;
- 不同的垃圾回收器,使用的算法不同
- 回收方法区,堆中的垃圾
3.1 垃圾回收的时机
- 创建对象/常量/类加载,先需要在某个内存区域分配内存空间,如果空间不足,则执行gc,如果gc还不足,就是OOM。
- java.lang.Object中有一个finalize()方法,当JVM确定不再指向该对象的引用时,垃圾回收器在对象上调用该方法。finalize()方法有点类似于对象周期的临终方法,JVM调用该方法,表示该对象即将"死亡",之后就可以会使用该对象了。注意回收还是在JVM中处理的,如果手动调用某个对象的finalize()方法,不会造成对象"死亡"。
3.2 判断垃圾的算法
3.2.1 引用计数算法
- 有增加某个对象的引用,该对象引用计数器+1,减少计数器-1
- 缺陷:无法解决循环引用的问题,主流的JVM中,都没有使用该算法
3.2.2 可达性分析算法
- 此算法的核心思想为:通过一系列称为" GC Roots"(线程运行时,局部变量(引用)指向的是一项)的对象作为起始点,从这些节点开始向下搜索(看对象中的成员变量,搜索走过的路径称之为"引用链",当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的。
3.3 回收的内存区域
3.3.1 回收方法区
- 在1.7里面叫做方法区(Method Area),1.8称为元空间(Metaspace)
- gc中,方法区称为永久代(方法区/元空间的概念,不是真实JVM实现的依赖,只是表达了要存放什么样的数据)
- gc叫永久代,属于真实的jvm内部gc的实现时,使用的内存描述,
- 虽然叫做永久代,但是不意味着对象在这块区域是永久存活的,还是可以回收,只是回收效率,效率都比较低。
3.3.2 回收堆
- gc中,把堆也称为gc堆
3.4垃圾回收算法
3.4.1 标记清除算法(老年代的回收算法)
- 分为两个阶段:
- 标记:标记无用对象(使用不可达分析算法)
- 清除:清除标记的垃圾
- 标记- 清除算法的不足主要有两个
- 效率问题:标记和清除两个过程的效率都不高
- 空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大的随想时,无法找到足够连续内存而不得不提前触发下一次的GC。
3.4.2 复制算法(新生代回收算法)
- 优点:
- 新生代中的对象,大部分都是朝生夕死(创建出来以后,很快就不可达),复制存活对象,性能很高(存活对象很少)
线程调用方法:方法中局部变量的方式创建对象,方法栈帧出栈(方法返回),堆中对象就不可达。 - 没有内存碎片的问题
- 缺点:内存的利用率不高,只有50%
- 复制算法的优化方案:提高新生代内存的利用率。
- 将内存(新生代内存)分为一块较大的Eden(伊甸区)空间和两块较小的Survivor(幸存者)空间,每次使用Eden和其中的一块Survivor(两个Survivor区域称为一个From区,一个To区)HotSpot默认Eden与Survivor的大小比例是8:1,也就是说Eden:Survivor From :Survivor To = 8:1:1,所以每次新生代可用内存空间为整个新生代容量的90%,只有10%的会被浪费。
3.4.3标记整理算法(老年代的回收算法)
- 对象存活率较高的情况使用。
- 根据老年代的特点,提出了一种称之为"标记-整理算法",标记过程和标记清除算法中的标记是一样的,后续步骤不是直接对可回收对象进行清理,而是让所有的存货对象向一端移动,然后清理掉端边界以外的内存。
- 优点:没有内存碎片的问题。
3.4.4 分代收集算法
- 属于一种算法思想,没有算法实现。具体来说,把堆话划分为好几块。
- (新生代:Eden区,S0,S1),使用复制算法的升级版
- (老年代):使用标记清除算法或者标记整理算法。
- 新生代gc,又称为Yong GC ,minor GC (指对用户线程的影响较小),表现是:对象的存活率是较低的,回收效率非常高,效率也较高。
- 老年代GC,又称为Old GC,major gc(指对用户线程影响较大),回收速度是比新生代慢10倍。