jvm初识
上面对运行时数据区描述了很多,其实重点存储数据的是堆和方法区(非堆),所以内存的设计也着重从 这两方面展开(注意这两块区域都是线程共享的)。对于虚拟机栈,本地方法栈,程序计数器都是线程私有的。
官网:https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4
java 内存模型,和jvm 内存模型不要搞混
(1)引用计数法
对于某个对象而言,只要应用程序中持有该对象的引用,就说明该对象不是垃圾,如果一个对象没有任 何指针对其引用,它就是垃圾。
(2)可达性分析
通过GC Root的对象,开始向下寻找,看某个对象是否可达。
能作为GC Root: 类加载器、Thread、虚拟机栈的本地变量表、static成员、常量引用、本地方法栈的变量等。
标记
复制
缺点
1 存在大量的复制操作,效率会降低
2 空间利用率降低
垃圾收集算法选择
Young区:复制算法(对象在被分配之后,可能生命周期比较短,Young区复制效率比较高)
Old区:标记清除或标记整理(Old区对象存活时间比较长,复制来复制去没必要,不如做个标记再清理)
如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。
ava8 官 网 : https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#sthref27
Java17 官 网 :https://docs.oracle.com/en/java/javase/17/gctuning/available- collectors.html#GUID-F215A508-9E58-40B4-90A5-74E29BF3BD3C
可以用于新老年代新生代: 复制算法
老年代: 标记-整理算法
The serial collector uses a single thread to perform all garbage collection work
官 网 : https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html#concurrent_mark_
可以用于老年代
采用标记-清除算法
回收过程:https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html
可以用于新老年代
整体上采用标记-整理算法
回收过程:https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html
停顿时间->垃圾收集器 进行 垃圾回收终端应用执行响应的时间
吞吐量->运行用户代码时间/(运行用户代码时间+垃圾收集时间)
GC是由JVM自动完成的,根据JVM系统环境而定,所以时机是不确定的。
当然,我们可以手动进行垃圾回收,比如调用System.gc()方法通知JVM进行一次垃圾回收,但是具体什么时刻运行也无法控制。也就是说System.gc()只是通知要回收,什么时候回收由JVM决定。但是不建议手动调用该方法,因为GC消耗的资源比较大
User.java源码文件是Java这门高级开发语言,对程序员友好,方便我们开发。
javac编译器将User.java源码文件编译成class文件[我们把这里的编译称为前期编译],交给JVM运行,因为JVM只能认识class字节码文件。同时在不同的操作系统上安装对应版本的JDK,里面包含了各自屏蔽操作系统底层细节的JVM, 这样同一份class文件就能运行在不同的操作系统平台之上,得益于JVM。这也是Write Once,Run Anywhere的原因所在。
最终JVM需要把字节码指令转换为机器码,可以理解为是0101这样的机器语言,这样才能运行在不同的机器上,那么由字节码转变为机器码是谁来做的呢?说白了就是谁来执行这些字节码指令的呢?这就是执行引擎里面的解释执行器和编译器所要做的事情。
Interpreter,解释器逐条把字节码翻译成机器码并执行,跨平台的保证。
刚开始执行引擎只采用了解释执行的,但是后来发现某些方法或者代码块被调用执行的特别频繁时,就 会把这些代码认定为“热点代码”。
Just-In-Time compilation(JIT),即时编译器先将字节码编译成对应平台的可执行文件,运行速度快。即时编译器会把这些热点代码编译成与本地平台关联的机器码,并且进行各层次的优化,保存到内存中。
HotSpot虚拟机里面内置了两个JIT:C1和C2
Java7开始,HotSpot会使用分层编译的方式
也就是会结合C1的启动性能优势和C2的峰值性能优势,热点方法会先被C1编译,然后热点方法中的热点会被C2再次编译
在Java9中,引入了AOT(Ahead of Time)编译器
即时编译器是在程序运行过程中,将字节码翻译成机器码。而AOT是在程序运行之前,将字节码转换为机器码
官网:https://www.graalvm.org/
在Java10中,新的JIT编译器Graal被引入。它是一个以Java为主要编程语言,面向字节码的编译器。跟
C++实现的C1和C2相比,模块化更加明显,也更加容易维护。
Graal既可以作为动态编译器,在运行时编译热点方法;也可以作为静态编译器,实现AOT编译。
除此之外,它还移除了编程语言之间的边界,并且支持通过即时编译技术,将混杂了不同的编程语言的 代码编译到同一段二进制码之中,从而实现不同语言之间的无缝切换。
Spring Native 和 Dubbo Native
Spring Native:https://spring.io/blog/2021/03/11/announcing-spring-native-beta
Dubbo Native:https://dubbo.apache.org/zh/docs/references/graalvm/support-graalvm/