Java核心知识点梳理(一)

Java核心知识点梳理(一)

Java程序是怎么执行的?

  1. 先把Java代码编译成class字节码,大致流程是:Java源代码 --> 词法分析器 --> 语义分析器 --> 字节码生成器 --> 字节码;
  2. 将.clsss文件放入Java虚拟机,通常是Oracle官方自带的hotspot jvm
  3. JVM使用类加载器装载class文件;
  4. 类加载完成后,进行字节码校验,校验通过后JVM解释器会把字节码翻译成机器码交给操作系统解释执行,但不是所有代码都解释执行,例如hotspot jvm提供了JIT(Just In Time)也就是动态编译器,在运行时将热点代码编译为机器码,这时字节码就变成了编译执行;

JVM如何判定热点代码?

  • 基于采样的热点判定

    JVM会周期性检查各个线程的栈顶,若某个方法经常出现在栈顶,那这个方法就是热点方法,优点是实现简单,缺点是缺少精确性,很容易受到线程阻塞或外界因素的影响

  • 基于计时器的热点判定

    主要就是虚拟机给每一个方法甚至代码块建立了一个计数器,统计方法的执行次数,超过一定的阀值则标记为此方法为热点方法。

    Hotspot 虚拟机使用的基于计数器的热点探测方法。它使用了两类计数器:方法调用计数器回边计数器,当到达一定的阀值是就会触发 JIT 编译。

    方法调用计数器:在 client 模式下的阀值是 1500 次,Server 是 10000 次,可以通过虚拟机参数: -XX:CompileThreshold=N 对其进行设置。但是JVM还存在热度衰减,时间段内调用方法的次数较少,计数器就减小。

    回边计数器:主要统计的是方法中循环体代码执行的次数。

Java内存泄漏的常见场景

  • 长生命周期对象持有短生命的引用,比如,缓存系统,我们加载了一个对象放在缓存中,然后一直不使用这个缓存,由于缓存的对象一直被缓存引用得不到释放,就造成了内存泄漏;
  • 各种连接未调用关闭方法,比如,数据库 Connection 连接,未显性地关闭,就会造成内存泄漏;
  • 内部类持有外部类,如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持有外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露;
  • 改变哈希值,当一个对象被存储进 HashSet 集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则对象修改后的哈希值与最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用作为的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中单独删除当前对象,造成内存泄露。
posted @ 2019-10-07 15:04  bodhisatan  阅读(518)  评论(0编辑  收藏  举报