先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。其关系模型图如下图所示:
4. JVM 调优,查看 JVM 参数默认值
-
jps -v 可以查看 jvm 进程显示指定的参数
-
使用 -XX:+PrintFlagsFinal 可以看到 JVM 所有参数的值
-
jinfo 可以实时查看和调整虚拟机各项参数
-
jstat -gc 12538 5000即会每5秒一次显示进程号为12538的java进程的GC情况
5. OOM排查方法
1)先查看应用进程号pid:ps -ef | grep 应用名
2)查看pid垃圾回收情况: jstat -gc pid 5000(时间间隔)
3)开启OOM快照:
-XX:+HeapDumpOnOutOfMemoryError(开启堆快照)
-XX:HeapDumpPath=C:/m.hprof(保存文件到哪个目录)
4)dump 查看方法栈信息:jstack -l pid > /home/test/jstack.txt
5)dump 查看JVM内存分配以及使用情况:jmap -heap pid > /home/test/jmapHeap.txt
6)dump jvm二进制的内存详细使用情况
6. 类加载
- 类加载器:
- 类加载过程:加载,验证,准备,解析,初始化
-
加载:加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的入口。
-
验证:确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
-
准备:准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使用的内存空间。
-
解析:解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程。
-
初始化:初始化阶段是执行类构造器方法的过程。到了初始阶段,才开始真正执行类中定义的Java程序代码。
-
双亲委派模型
-
定义:除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器,这里类加载器之间的父子关系一般通过组合(Composition)关系来实现,而不是通过继承(Inheritance)的关系实现。
-
工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载,而是把这个请求委派给父类加载器,每一个层次的加载器都是如此,依次递归,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成此加载请求(它搜索范围中没有找到所需类)时,子加载器才会尝试自己加载。
-
优点:使用双亲委派模型来组织类加载器之间的关系,使得Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放再rt.jar中,无论哪个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。
-
打破双亲委派机制的方法:重写loadclass()方法
-
打破双亲委派机制的例子:
-
Tomcat,应用的类加载器优先自行加载应用目录下的 class,并不是先委派给父加载器,加载不了才委派给父加载器。打破的目的是为了完成应用间的类隔离。
-
JDK 9,Extension ClassLoader 被 Platform ClassLoader 取代,当平台及应用程序类加载器收到类加载请求,在委派给父加载器加载前,要先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就要优先委派给负责那个模块的加载器完成加载。打破的原因,是为了添加模块化的特性。
-
沙箱安全机制:防止恶意代码污染java源代码。
7. JVM加载class文件的原理
JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件的类。
Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的类。
类装载方式,有两种
-
隐式装载,程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中
-
显式装载,通过class.forname()等方法,显式加载需要的类,隐式加载与显式加载的区别:两者本质是一样的。
Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销。
8. GC Roots
作为GCRoots的对象包括下面几种:
1)虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。
2)方法区中的类静态属性引用的对象。
3)方法区中常量引用的对象。
4)本地方法栈中JNI(Native方法)引用的对象。
9. 对象可达性分析
-
如果对象在进行可达性分析后发现没有与GCRoots相连的引用链,则该对象被第一次标记并进行一次筛选,筛选条件为是否有必要执行该对象的finalize方法,若对象没有覆盖finalize方法或者该finalize方法是否已经被虚拟机执行过了,则均视作不必要执行该对象的finalize方法,即该对象将会被回收。反之,若对象覆盖了finalize方法并且该finalize方法并没有被执行过,那么,这个对象会被放置在一个叫F-Queue的队列中,之后会由虚拟机自动建立的、优先级低的Finalizer线程去执行,而虚拟机不必要等待该线程执行结束,即虚拟机只负责建立线程,其他的事情交给此线程去处理。
-
对F-Queue中对象进行第二次标记,如果对象在finalize方法中拯救了自己,即关联上了GCRoots引用链,如把this关键字赋值给其他变量,那么在第二次标记的时候该对象将从“即将回收”的集合中移除,如果对象还是没有拯救自己,那就会被回收。
10. 垃圾回收机制
堆分为新生代和老年代,新生代默认占总空间的 1/3,老年代默认占 2/3。新生代使用复制算法,有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1。
当新生代中的 Eden 区内存不足时,就会触发 Minor GC,过程如下:
1)在 Eden 区执行了第一次 GC 之后,存活的对象会被移动到其中一个 Survivor 分区;
2)Eden 区再次 GC,这时会采用复制算法,将 Eden 和 from 区一起清理,存活的对象会被复制到 to 区;
3)移动一次,对象年龄加 1,对象年龄大于一定阀值会直接移动到老年代
4)Survivor 区相同年龄所有对象大小的总和 > (Survivor 区内存大小 * 目标使用率)时,大于或等于该年龄的对象直接进入老年代。其中这个使用率通过 -XX:TargetSurvivorRatio 指定,默认为 50%
5)Survivor 区内存不足会发生担保分配
6)年龄超过指定大小的对象可以直接进入老年代
7)Major GC,指的是老年代的垃圾清理,但并未找到明确说明何时在进行Major GC
8)FullGC,整个堆的垃圾收集,触发条件:
-
每次晋升到老年代的对象平均大小>老年代剩余空间
-
MinorGC后存活的对象超过了老年代剩余空间
-
元空间不足
-
System.gc()
-
CMS GC异常,promotion failed:MinorGC时,survivor空间放不下,对象只能放入老年代,而老年代也放不下造成;concurrent mode failure:GC时,同时有对象要放入老年代,而老年代空间不足造成
-
堆内存分配很大的对象
11. 垃圾回收算法
-
引用计数法:给对象中添加一个引用计数器,每当一个地方引用这个对象时,计数器值+1;当引用失效时,计数器值-1。任何时刻计数值为0的对象就是不可能再被使用的。
-
缺点:(1)每次给对象赋值时都要维护引用计数器,且计数器本身也有一定的消耗;(2)较难处理循环引用
-
复制算法:(年轻代)
-
优点:(1)不产生内存碎片;(2)速度快
-
缺点:浪费10%的内存空间
-
标记清除算法(老年代):先标记出要回收的对象,然后统一回收这些对象
-
优点:节省空间
-
缺点:产生内存碎片;
-
标记整理算法(老年代):先标记清除,再次扫描并往一端滑动存活对象。
-
优点:不产生内存碎片;
-
缺点:需要移动对象的成本,耗时严重
12. 垃圾收集器
1)Serial收集器:新生代收集器,使用停止复制算法,使用一个线程进行GC,其它工作线程暂停。使用-XX:+UseSerialGC可以使用Serial+Serial Old模式运行进行内存回收(这也是虚拟机在Client模式下运行的默认值)
2)Serial Old收集器:老年代收集器,单线程收集器,使用标记整理(整理的方法是Sweep(清理)和Compact(压缩),清理是将废弃的对象干掉,只留幸存的对象,压缩是将移动对象,将空间填满保证内存分为2块,一块全是对象,一块空闲)算法,使用单线程进行GC,其它工作线程暂停(注意,在老年代中进行标 记整理算法清理,也需要暂停其它线程),在JDK1.5之前,Serial Old收集器与ParallelScavenge搭配使用。
最后
小编利用空余时间整理了一份《MySQL性能调优手册》,初衷也很简单,就是希望能够帮助到大家,减轻大家的负担和节省时间。
关于这个,给大家看一份学习大纲(PDF)文件,每一个分支里面会有详细的介绍。
这里都是以图片形式展示介绍,如要下载原文件以及更多的性能调优笔记(MySQL+Tomcat+JVM)!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
示介绍,如要下载原文件以及更多的性能调优笔记(MySQL+Tomcat+JVM)!**
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-Ia6IYS1Z-1713439302202)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!