【每日鲜蘑】学习JAVA必须知道的知识
2020/6/29 17:26:24
本文主要是介绍【每日鲜蘑】学习JAVA必须知道的知识,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
简单梳理Java知识时,整理的笔记,分享一下,如有错误,还请指正,谢谢🙏
编译过程
编译由 Java 源码编译器(javac)来完成。
过程:源代码---【词法分析器】---Token 流---【语法分析器】---语法树---【语义分析器】---注解抽象语法树---【字节码生成器】---JVM 字节码
三个过程
解析与填充符号表 注解处理 分析和字节码生成
语法糖【泛型】
泛型只会在 Java 源码中存在,编译过后会被替换为原来的原生类型(Raw Type,也称为裸类型)了。这个过程也被称之为“泛型擦除”。
代码更加简洁【不用强制转换】 程序更加健壮【只要编译时期没有警告,那么运行时期就不会出现 ClassCastException 异常】 可读性和稳定性【在编写集合的时候,就限定了类型】
跨平台运行
字节码是不区分系统的,而 JDK 是区分系统的。各个平台编译的字节码都符合 JVM 的规范,从而做到一次编译到处运行。
类的加载
不是所有的类都会被加载到 JVM 的,Java 类的加载是动态的,只有在需要用到的时候才会被加载,这样节省了内存开销。
默认的类加载器
启动类加载器:【Bootstrap ClassLoader】负责加载$JAVA_HOME 中 jre/lib/rt.jar里所有的 class,由 C++实现,不是 ClassLoader 子类。 扩展类加载器【Extension ClassLoader】负责加载 java 平台中扩展功能的一些 jar 包,包括$JAVA_HOME 中 jre/lib/*.jar 或-Djava.ext.dirs 指定目录下的 jar 包。 应用类加载器【Application ClassLoader】负责记载classpath中指定的 jar 包及目录中 class。 用户自定义类加载器【User ClassLoadder】
双亲委派【解决安全性问题】
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上。
好处: 防止内存中出现多份同样的字节码(安全性角度)
类加载器在成功加载某个类之后,会把得到的 java.lang.Class 类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。
通过自定义 ClassLoader,并重写父类的 loadClass 方法可以打破双亲委派的机制,而 Java 的 SPI(服务提供发现机制)也是打破双亲委派机制的。
详细过程
加载,查找并加载类的二进制数据,在 Java 堆中也创建一个 java.lang.Class 类的对象。 连接,连接又包含三块内容:验证、准备、初始化。 1)验证,文件格式、元数据、字节码、符号引用验证; 2)准备,为类的静态变量分配内存,并将其初始化为默认值; 3)解析,把类中的符号引用转换为直接引用
初始化,为类的静态变量赋予正确的初始值。
JIT 即时编译器
【Just In Time】将热点代码的字节码重新编译优化,让 CPU 直接执行,这样的执行效率会更高。HotSpot 是基于计数器来检测热点代码的而非采样。
类加载完后
在类加载检查通过后,接下来虚拟机将为新生对象分配内存。
JVM 的垃圾回收算法
通过“可达性分析算法”分析哪些对象是垃圾,然后通过垃圾回收算法进行回收。
Serial 收集器,串行收集器是最古老,最稳定以及效率高的收集器,但可能会产生较长的停顿,只使用一个线程去回收。 ParNew 收集器,ParNew 收集器其实就是 Serial 收集器的多线程版本。 Parallel 收集器,Parallel Scavenge 收集器类似 ParNew 收集器,Parallel 收集器更关注系统的吞吐量。 Parallel Old 收集器,Parallel Old 是 Parallel Scavenge 收集器的老年代版本,使用多线程“标记-整理”算法 CMS 收集器,CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它需要消耗额外的 CPU 和内存资源,在 CPU 和内存资源紧张,CPU 较少时,会加重系统负担。CMS无法处理浮动垃圾。CMS 的“标记-清除”算法,会导致大量空间碎片的产生。 G1 收集器,G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征。
JVM 内存模型
JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。
栈管运行,堆管存储。
JVM 内存会划分为堆内存和非堆内存,堆内存中也会划分为年轻代和老年代,而非堆内存则为永久代(方法区、元空间)。
年轻代又会分为 Eden 和 Survivor 区。Survivor 也会分为 FromPlace 和 ToPlace,toPlace 的 survivor 区域是空的。Eden,FromPlace 和 ToPlace 的默认占比为 8:1:1。
当然这个东西其实也可以通过一个 -XX:+UsePSAdaptiveSurvivorSizePolicy 参数来根据生成对象的速率动态调整
内存泄漏&内存溢出
内存泄漏:对象可达,但是对象不会被使用。 内存溢出:装载类的空间不够、内存空间不足、内存泄漏等等都可能导致溢出。
线程栈
JVM 规范让每个 Java 线程拥有自己的独立的 JVM 栈,也就是 Java 方法的调用栈。
当方法调用的时候,会生成一个栈帧。栈帧是保存在虚拟机栈中的,栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息
线程运行过程中,只有一个栈帧是处于活跃状态,称为“当前活跃栈帧”,当前活动栈帧始终是虚拟机栈的栈顶元素。
JVM 年轻代到年老代的晋升过程的判断条件是什么
部分对象会在 From 和 To 区域中复制来复制去,如此交换 15 次(由 JVM 参数 MaxTenuringThreshold 决定,这个参数默认是 15),最终如果还是存活,就存入到老年代; 如果对象的大小大于 Eden 的二分之一会直接分配在 old,如果 old 也分配不下,会做一次 majorGC,如果小于 eden 的一半但是没有足够的空间,就进行 minorgc 也就是新生代 GC; minor gc 后,survivor 仍然放不下,则放到老年代; 动态年龄判断 ,大于等于某个年龄的对象超过了 survivor 空间一半 ,大于等于某个年龄的对象直接进入老年代;
JVM 出现 fullGC 很频繁,怎么去线上排查问题
是不是频繁创建了大对象(也有可能 eden 区设置过小)(大对象直接分配在老年代中,导致老年代空间不足--->从而频繁 gc) 是不是老年代的空间设置过小了(Minor GC 几个对象就大于老年代的剩余空间了) 1. 如果一次 full GC 后,剩余对象不多,那么说明 Eden 的空间设置太小,导致大量短生命周期的对象被分配到了老生代。 2. 如果一次 full GC 后,老生代的变化不大,那么是老生代分配空间太小了。
JVM 垃圾回收机制,何时触发 MinorGC 等操作
当 young gen 中的 eden 区分配满的时候触发 MinorGC(新生代的空间不够放的时候).
这篇关于【每日鲜蘑】学习JAVA必须知道的知识的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-01后台管理开发学习:新手入门指南
- 2024-11-01后台管理系统开发学习:新手入门教程
- 2024-11-01后台开发学习:从入门到实践的简单教程
- 2024-11-01后台综合解决方案学习:从入门到初级实战教程
- 2024-11-01接口模块封装学习入门教程
- 2024-11-01请求动作封装学习:新手入门教程
- 2024-11-01登录鉴权入门:新手必读指南
- 2024-11-01动态面包屑入门:轻松掌握导航设计技巧
- 2024-11-01动态权限入门:新手必读指南
- 2024-11-01动态主题处理入门:新手必读指南