java基础重铸——JVM篇

    • JVM
      1. JVM概述
        Jvm是Java虚拟机,用来执行Java文件生成的字节码(*.class文件)的虚拟机。
        Jvm是执行在操作系统之上的软件,与底层硬件不相关。Java的跨平台特性就在于使用Jvm和不同操作系统的组合,屏蔽了不同硬件的差异,适应了不同的操作系统的Jvm可以任意执行Java代码
      2. Jvm的内部结构
        类加载器:ClassLoader(java.lang.ClassLoader)


Jvm运行时内存结构(Jvm进程的内存结构):
Method Area(方法区):
和堆区一样和各个线程共享;
JVM启动时创建;
实际物理内存可以和堆区一样可以不连续;
方法区的大小决定了系统可以保存多少个类;
会抛出OOM(java.lang.OutOfMemoryError)异常(OOM:PermGen space & OOM:Metaspace):
永久代/持久代(PermGen space)在JDK8中被元空间(Metaspace)取代,方法区移至Metaspace,字符串常量移至Java Heap。常见导致OOM的原因:加载大量第三方Jar包;Tomcat工程太多;大量动态生成反射类;
主要作用:
存储程序运行时长期存活的对象,比如:类的元数据、方法、常量、属性等
Heap(堆):
和方法区一样和各个线程共享;
JVM启动时创建;
实际物理内存可以不连续;
主要作用:
存放对象实例。GC 垃圾回收器只要回收堆内存的对象
堆内存分为
年轻代(Young Generation)、老年代(Old Generation)
年轻代又分为生成区(Eden-伊甸园)和幸存区(Survivor-幸存者)

幸存区又分为FromSpace和ToSpace组成(解决碎片化的问题)

年轻代:FromSpace:ToSpace = 8:1:1

为什么分代:针对不同的对象的存活概率进行分类,提升GC执行效率
Jvm Stacks(虚拟机栈):

JVM虚拟机栈的生命周期与执行的线程保持一致;

Jvm虚拟机栈是当前执行线程占空间,以栈的数据结构的形式存在(一个线程对应一个JVM Stack => 每个JVM Stack包含一组Stack Frame; 线程每调用一个方法就对应着Jvm Stack中一个Stack Frame入栈,当方法执行完毕或者异常终止对应着Stack Frame出栈/销毁;当JVM调用一个Java方法时它从对应的类型信息中获取该方法的局部变量区和操作数栈的大小,并据此分配栈帧内存,然后将栈帧压入JVM虚拟机栈中);

Jvm虚拟机是线程运算执行的区域,它保存着一个线程方法调用的顺序和过程;
被执行的方法都是以栈帧(frame)的结构压入Jvm虚拟机栈;

当Jvm虚拟机栈的空间不够使用时,将报出stackoverflowException;
JVM 虚拟机堆栈调优参数:-Xss2M
PC Register(程序计数器):记录当前线程执行字节码的行号指示器

每个线程拥有独立的线程计数器;

执行Java方法时,程序计数器记录正在执行的字节码指令的地址

执行Native本地方法时程序计数器值为空
Native Method Stacks(本地方法栈):
执行操作系统本地的方法;

抛出StackOverflowError和OutOfMemoryError异常;
执行的方法等同于Jvm

元空间:元空间和永久代都是堆方法区的实现,区别是元空间不在Jvm中,而是使用的本地内存
执行引擎:
JIT编译器:编译执行; 一般热点数据会进行二次编译,将字节码指令变成机器指令。将机器指令放在方法区缓存。
解释器:逐行解释字节码文件内容
GC 垃圾回收:

GC垃圾回收算法:

标记清除:优点:占用内存小;缺点:两次动作(标记、清除)低效、内存碎片

标记整理:优点:占用内存小、没有内存碎片;缺点:两次动作(标记、清除)低效

复制算法:优点:高效;缺点:占用内存

引用计数:缺点无法解决循环引用

分代收集:区分不同的对象生命周期,针对各个年代对象的特点针对清除

垃圾收集器(在HotSpot的实现中,是使用一组称为OopMap的数据结构来知道哪些地方存放着对象引用):

串行收集器:单线程,应用线程等待

并行收集器:多线程并行,应用线程等待

CMS收集器(标记清除算法 ):缩短应用暂停时间

G1收集器:维护优先列表保证短时间内回收效率最高
OOM问题常见原因:

老年代内存不足:java.lang.OutOfMemoryError:Javaheapspace

永久代内存不足:java.lang.OutOfMemoryError:PermGenspace

代码bug,占用内存无法及时回收
调优建议:

选择高效的GC算法,可有效减少停止应用线程时间。

频繁Full GC会增加暂停时间和CPU使用率,可以加大老年代空间大小降低Full GC,但会增加回收时间,根据业务适当取舍

      1. JVM 三大虚拟机:
        Sun HotSpot:SunJDK和OpenJDK自带的虚拟机(java -v 即可查询到使用的虚拟机类型Java HotSpot(TM))
        BEA JRocket:不包含解析器实现,全部代码均靠即使编译器编译后执行
        iBM J9:类似HotSpot,在IBM的Java产品中使用
      2. 类加载子系统
        系统加载的类加载器(父委托机制):
        BootstrapClassLoader (祖父:启动类加载器):加载jre/lib/*下面的核心代码(rt.jar);C++编写;但在通过ExtClassLoader.getParent()获取到的是null(类加载器部分:null就是指BootstrapClassLoader)
        ExtClassLoader (爷爷:扩展类加载器):加载jre/lib/ext/*下的扩展包(dnsns.jar之类);Java编写;位于sun.misc包下(rt.jar),导入源码中无
        AppClassLoader (父亲:应用程序类加载器):加载CLASSPATH路径下的包(用户自定义类);Java编写;位于sun.misc包下(rt.jar),导入源码中无
        XXXClassLoader(XX:用户自定义类加载器):通过继承java.Lang.ClassLoader的方式实现用户自定义加载类;在编写自定义类加载器时候,如果没有太过复杂的要求,可以直接继承URLclassloader类,这样可以避免自己去写findclass()方法,及其获取字节码流的方式,使自定义类加载器更加方便


 

 

 

JVM全局加载流程图

 

Jvm入口:sun.misc.Launcher(rt.jar)
获取ClassLoader的途径:

 

 

 


双亲委派机制:类加载器接收到加载请求,优先将请求委托给父类去执行。如果父类加载器无法完成请求,则子加载器才会去自己尝试加载(这种方式使得java中的类随着他的类加载器一起具备了一种带有优先级的层次关系,会保证系统的类不会受到恶意的攻击)
优势:避免了类的重复加载;保护核心API,防止被随意篡改

父委托机制流程图

 

 

 

 

      1. 运行时数据区(线程独有):程序计数器、虚拟机机栈、本地方法栈
        本地方法栈区域没有垃圾回收机制,堆和方法区有垃圾回收机制,pc寄存器也没有垃圾回收机制。

OOM:内存溢出异常,pc寄存器没有内存溢出情况,但是虚拟机栈区域和本地方法栈区域可能有内存溢出情况,heap area,method area也可能发生内存的溢出情况。

Pc寄存器既没有GC也没有OOM
线程的概念:
在hotspot虚拟机里,每一个线程都与操作系统的本地线程直接映射,每当一个java线程准备好执行以后,此时一个操作系统的本地线程也同时创建,java线程执行终止后,操作系统的本地线程也会被回收;操作系统负责所有线程的安排调度到任何一个可用的cpu上,一旦本线程初始化成功,就会调用java线程中的run()方法。在这里准备工作是准备一个线程所需要的资源,比如本地方法栈,程序计数器,虚拟机栈。
JVM 线程分类(后台系统线程):
Jvm线程:虚拟机线程在JVM达到安全点(所有应用线程能够停顿的位置)时触发,比如“stop-the-world”的垃圾回收时(停止所有线程来进行可达性分析)、线程栈收集、线程挂起以及偏向锁撤销
周期任务线程:这种线程是时间周期事件的体现(比如中断),他们一般用于周期性操作的调度执行

GC任务线程:Jvm中不同种类的垃圾收集线程

编译线程:运行时将字节码文件编译为本地代码

信号调度线程(守护线程):接收信号并发送给jvm,在JVM内部通过调用适当的方法进行处理

程序计数器:

 

参考资料
jvm学习笔记:https://www.kancloud.cn/luoyoub/jvm-note/1890100
Jvm系列-Jvm概述(一)_:https://blog.csdn.net/qq_38163244/article/details/109551205
JVM堆内存(heap)详解:https://blog.csdn.net/lingbo229/article/details/82586822
JVM-Stacks 虚拟机栈:https://blog.csdn.net/weixin_46919552/article/details/107579422
Java JVM 栈帧(Stack Frame):https://www.cnblogs.com/jhxxb/p/11001238.html
类加载器ClassLoader源码解析 - 赵计刚:https://www.cnblogs.com/java-zhao/p/5201291.html
Jvm系列-类加载子系统(二)_:https://blog.csdn.net/qq_38163244/article/details/109559898

java BootstrapClassLoader/ExtClassLoader/AppClassLoader的加载路径及"父委托机制":https://blog.csdn.net/kidari/article/details/100018263
JVM系列-运行时数据区(一)_:https://blog.csdn.net/qq_38163244/article/details/109708467
JVM系列-运行时数据区(二)_:https://blog.csdn.net/qq_38163244/article/details/109982547

 

 

 

posted @ 2022-02-10 13:06  信念是基石  阅读(65)  评论(0编辑  收藏  举报
跟随粒子特效