黑马程序员JVM完整教程,Java虚拟机快速入门,全程干货不拖沓









栈帧过多

栈帧过大



Java虚拟机有一个方法区,是所有Java虚拟之间共享机线程。
方法区域类似于编译代码的存储区域
传统的语言或类似于“文本”段在一个操作系统
的过程。
它存储每个类结构运行时常量池等领域
方法数据和方法和构造函数的代码,包括特别
方法用于类和实例初始化和接口初始化。
方法区上创建虚拟机启动的方法。
虽然方法区逻辑上堆的一部分,简单的实现可以选择不垃圾收集或紧凑。
本规范并不强制的位置的方法

·1.8以前会导致永久代内存溢出
·1.8之后会导致元空间内存溢出




记住new 都是堆内存

永久代回收效率低
直接内存! gc不能 unsafe

垃圾回收
GCROOTs




https://blog.csdn.net/linzhiqiang0316/article/details/88591907
https://blog.csdn.net/weixin_43338519/article/details/107836096

参数配置

并发标记打扫



gc 调优


越大时间也会越长

初始标记:仅仅标记GC ROOTS的直接关联对象,并且世界暂停
并发标记:使用GC ROOTS TRACING算法,进行跟踪标记,世界不暂停
重新标记,因为之前并发标记,其他用户线程不暂停,可能产生了新垃圾,所以重新标记,世界暂停
- 新生代 GC(Minor GC):指发生新生代的的垃圾收集动作,Minor GC 非常频繁,回收速度一般也比较快。
- 老年代 GC(Major GC/Full GC):指发生在老年代的 GC,出现了 Major GC 经常会伴随至少一次的 Minor GC(并非绝对),Major GC 的速度一般会比 Minor GC 的慢 10 倍以上。
重新标记钱 先清理



附加属性_计数;






字节码一样



静态代码>构造方法
父>子
int


编译类型看左边 运行类型看右边

跟上例中的finally相比,发现没有athrow了,这告诉我们:如果在finally中出现了 return, 会吞掉异常,可以试一下下面的代码!!!
原来就是把要返回的值先保存到局部变量中,返回前再load到栈中返回
return 不受影响


一开始是new指令在堆上分配了内存并向操作数栈压入了指向这段内存的引用,之后dup指令又备份了一份,那么操作数栈顶就有两个,再后是调用invokespecial #18指令进行初始化,此时会消耗一个引用作为传给构造器的“this”参数,那么还剩下一个引用,会被astore_1指令存储当然new之后有时候会执行<init>,这主要依据字节码中是否包含invokespecial指令。下面主要说一下该指令
主要目的:得到对象存在堆中的地址,这样就可以用当前类,父类,父父类,即继承层的所有对象。 把继承层的所有对象的数据和方法为自己当前对象使用。到局部变量表中。

编译器处理
-127 -128 不会new


数组:直接fori

集合:迭代器

两次switch 防止hash冲突


JDKT开始新增了对需要关闭的资源处理的特殊语法try-with-resources:







final直接赋值
cinit 静态成员变量复制 初始化阶段/
将常量池中的符号引用解析为直接引用
字符串->地址
在类初始化之前的准备阶段,虚拟机会将类变量(static 修饰的变量)分配内存并设置零值。
在类初始化阶段,执行类构造器 <cinit>() 方法。<cinit> 类初始化方法有如下特点:
编译器会在将 .java 文件编译成 .class 文件时,收集所有类初始化代码和 static {} 域的代码,收集在一起成为 <cinit>() 方法;
子类初始化时会首先调用父类的 <cinit>() 方法;
JVM 会保证 <cinit>() 方法的线程安全,保证同一时间只有一个线程执行;


老师这个静态内部类利用的巧妙,调用Singleton函数,不会触发这个静态内部类的初始化,也就是不会创建这个单例对象

启动类加载路径

默认是使用本来的加载器加载依赖类的
由于JDBC在核心类库中,它由启动类加载器加载,由于驱动是在他的类初始化方法中加载的
于是要显示的调用Classd的forName方法使用一个能加载驱动的加载器加载驱动
1、我来总结下,在jre/lib包下有一个DriverManager,是启动类加载的,但是jdbc的驱动是各个厂商来实现的不在启动类加载路径下,启动类无法加载,而驱动管理需要用到这些驱动
1、SPI机制能够使接口与具体的实现类解耦, 可以根据实际的
业务情况启用或替换具体组件。
2、SPI机制为很多框架的扩展提供了可能。
3、SPI机制更多的是一种思想
3、过程就是:启动类加载器加载DriverManager,DriverManager代码里调用了线程上下文类加载器,这个加载器默认就是使用应用程序类加载器加载类,通过应用程序类加载器加载jdbc驱动

jmm



synchronized语句块既可以保证代码块的原子性,也同时保证代码块内变量的可见性。但缺点是
synchronized是属于重量级操作,性能相对更低

对iNSTANCE使用volatile修饰即可,可以禁用指令重排,但要注意在DK5以上的版本的volatile才会真正有效
CAS即Compare and Swap.,它体现的一种乐观锁的思想 与 volatile(易变的)

乐观锁与悲观锁
CAS是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也设关系,我吃亏点再重试呗。
synchronized是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。
juc (java.util.concurent)中提供了原子操作类,可以提供线程安全的操作,例如:AtomicInteger、AtomicBoolean等,它们底层就是采用CAS技术+volatile来实现的。




重量级锁没事,解锁就是

自旋成功

自旋失败会放弃
