Java-----JVM基础

Posted 小鹿可可乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java-----JVM基础相关的知识,希望对你有一定的参考价值。

1.JVM介绍

1.1JVM概念:

JVM即java虚拟机:JVM是利用软件来模拟计算机OS和硬件平台,在上面执行字节码文件,JVM有自己的架构,有堆栈,寄存器及指令系统

1.2 JVM特点

跨平台性:Java的跨平台性体现在Java代码“一次编译,到处执行”JVM是属于Java应用和操作系统中间的纽带的作用,将Java代码编程成字节码放在JVM上执行,JVM负责将字节码文件翻译为特定平台的机器码执行

2.JVM 工作过程

2.1 类加载系统

类加载机制:将Java的字节码文件.class加载到JVM中
类不会被初始化:

  • 同一个类在一个JVM实例中只会去被加载初始化一次
  • 在编译时能够确定的静态变量,不会对类进行初始化

2.1.1 类加载时机

  • 创建对象实例:New对象,前提是类被加载过
  • 通过class文件反射创建对象
  • 调用类静态属性或静态方法时
  • 初始化一个类的子类,使用子类时先初始化父类
  • 被标记为启动类的类,如main方法所在类

2.1.2 类加载

1.类加载器:

  • Bootstrap ClassLoader:启动类加载器:加载JDK包中/jre/lib/rt.jar中所有类
  • Extension ClassLoader:扩展类加载器:加载扩展功能的jar
  • Application ClassLoader:应用类加载器:负责加载classpath中指定的jar和目录中的class

2.双亲委派模型

  • 当前的类加载器从自己已经加载的类中查询是否此类已经加载,如果已经加载则返回原来已经加载的类
  • 如果没有找到,就去委派父类加载器去加载。父类加载器也会采用同样的策略,查看自己已经加载的类中是否包含这个类。有则返回,没有就委托其父类去加载。直到委托到启动类加载器为止。应因如果父类加载器为空,代表使用启动类加载作为父类去加载该类
  • 如果启动类加载器加载失败,就回会去使用扩展类加载器来尝试加载。继续失败则会使用APP ClassLoader来加载,如果存在自定义加载器就会到自定义加载器去尝试加载。继续失败就回去抛出一个异常:ClassNotFoundException.
    双亲委派模型的优势:安全性、避免类重复加载

2.1.3 类加载过程

1、加载:通过双亲委派机制将字节码文件加载到内存中
2、连接

  • 验证:验证元数据,字节码,符号引用
  • 准备:对类静态变量分配内存,初始化默认值
  • 解析:将符号应用转化为直接引用

3、初始化:类的静态变量赋予正确的初始值

2.2 运行数据区域

2.2.1 内存模型

1.程序计数器:

  1. 线程私有
  2. 内存模型中占用内存最小的一个区域
  3. 是当前程序执行字节码的行号指示器,实现代码的流程控制
  4. 不会出现OutOfMemoryError的内存区域
  5. 随着线程创建产生,随着线程结束而死亡

2.虚拟机栈

  1. 线程私有
  2. 是有一个个帧栈组成,每个帧栈是一个方法,用来描述程序方法执行的模型帧栈包含:局部变量表(数据类型,对象应用,返回地址)、操作数栈、动态链接、方法出口信息
  3. 异常:StackOverflowError:虚拟机栈的内存不允许动态扩容,栈内存不够时抛出该异常OutOfMemoryError:虚拟机栈的内存允许动态扩容,栈内存不够(无法扩展)时抛出异常
  4. 随着线程创建产生,随着线程结束而死亡

3.本地方法栈

  1. 线程私有
  2. 作用和虚拟机栈一样,区别在于执行时Native的方法服务
  3. 异常:StackOverflowError:虚拟机栈的内存不允许动态扩容,栈内存不够时抛出该异常OutOfMemoryError:虚拟机栈的内存允许动态扩容,栈内存不够(无法扩展)时抛出异常
  4. 随着线程创建产生,随着线程结束而死亡

4.堆

  1. 线程共享
  2. 内存模型中占用内存区域最大的空间
  3. 堆用来存放对象实例以及数组都存储在堆中
  4. 会抛出OutOfMemoryError异常
  5. 虚拟机创建是产生,虚拟机结束时销毁

5.方法区

  1. 线程共享
  2. 存储类信息,常量、静态变量存放在方法区
  3. 会抛出OutOfMemoryError异常
  4. 虚拟机创建是产生,虚拟机结束时销毁

2.垃圾回收

2.1 GC原理

1.将内存中不在被使用的对象进行回收,GC回收的方法称之为收集器,GC过程主要是回收对象,即主要是针对对空间,GC过程需要消耗资源和时间
2.Minor GC:对新生代的对象的收集
3.Full GC:对老年代的对象的收集,强制GC执行(System.gc)也是Full GC

2.2 对象被标记为垃圾的方法

1.引用计数器:存在无法解决循环引用问题

2.可达性分析
*从GCRoots遍历堆中对象,遍历完后没有被引用的节点即视为垃圾
*GC root:

  • 1、虚拟机栈中引用对象
  • 2、本地方法栈中的JNI引用对象
  • 3、方法区中静态变量和常量引用的对象

2.3 垃圾回收算法

2.3.1 标记清除

将对象回收分为标记和清除阶段,
标记阶段通过可达性分析标记从GCroot对象开始遍历所有可达的对象
清除阶段对对内存再次遍历,对未标记的对象进行回收
缺点:

  • 内存碎片化
  • 效率问题:两个阶段都是遍历堆的整个空间

2.3.2 复制算法

将堆内存空间分成大小两部分,每次使用其中一块,当这块快用完时,将存活的对象复制到另一个内存块中,将原对象空间一次性清除
优势:

  • 解决内存碎片化问题
  • 提高效率:每次只需要遍历堆空间的一半

缺点:

  • 内存缩小为原来一半,浪费空间,代价高
  • 极端情况,对象百分百存活就需要整个空间复制,耗时代价高

2.3.3 标记整理算法

将对象回收分为标记和整理两个阶段,标记阶段使用可达性分析遍历整个对=堆空间找到可达的对象,整理阶段将所有存活的对象向一段进行移动
优势:

  • 空间整个使用
  • 解决内存碎片化问题

缺点:

  • 效率不高,需要标记存活对象,遍历内存找到所有存活对象进行移动整理

2.3.4 分代回收算法

1.根据对象的存活时间的特点将内存空间划分为老年代和新生代
2.新生代:对象存活时间段,朝生夕灭-采用复制算法进行回收
3.老年代:经过多次GC存活下来的对象,存活时间上,采用标记清除或标记整理算法

3.JVM系统调优

3.1 调优原则

  1. 多数的应用不需要进行服务器上进行GC调优
  2. GC引起的问题多数是代码问题
  3. Java服务在部署之前都需要考虑将机器的JVM参数设置最优
  4. 减少创建对象的数量
  5. 减少使用全局变量和大对象
  6. GC调优是最优的额优化手段
  7. 在实际中,分析GC情况比优化GC要多

3.2 调优步骤

  1. 监控GC,内存使用等关键信息
  2. 分析结果,给出优化方案
  3. 调整GC类型和内存分配
  4. 需要不断分析调整

今天也要好好学习呀~

以上是关于Java-----JVM基础的主要内容,如果未能解决你的问题,请参考以下文章

Java JVM 相关基础知识

java基础总结大纲

Java JVM怎么学习啊?从哪方面入手?

Java基础学习总结(191)—— Oracle GraalVM 详细介绍

Java Jvm运行机制原理

Java虚拟机基础知识你知道多少?