【Java】快速入门JVM

文章目录

  • [1. JVM简介](#1. JVM简介)
  • [2. 类加载简介](#2. 类加载简介)
  • [3. 类加载的过程](#3. 类加载的过程)
  • [4. 双亲委派](#4. 双亲委派)
  • [5. GC垃圾回收](#5. GC垃圾回收)
  • [6. JVM的回收方式](#6. JVM的回收方式)
  • [7. 分代回收](#7. 分代回收)

1. JVM简介

JVM(Java虚拟机)是一个名字为Java的进程,是用于执行Java程序的虚拟机。

JVM会从操作系统中申请一大块内存空间,又把这个内存空间划分成为几个小的区域

区域的划分:

  1. 方法区
  2. 栈(Java虚拟栈和本地方法栈)
  3. 程序计数器
  4. 运行时常量池

代码中的局部变量是放在栈上的,成员变量放在堆上,静态变量放在方法区中,程序计数器放的是下一个要执行的指令地址

一个JVM进行中,堆和方法区只有一份,单栈和程序计数器,每个线程都有自己的一份

补充: 方法区的概念是jdk1.8之前的叫法,而jdk1.8之后没有方法区了,而多了个元数据区.

方法区是JVM申请内存中划分出的一个区域,而元数据区时是用的本地内存

2. 类加载简介

类加载是JVM将类的字节码加载到内存中,并进行验证、准备和解析的过程。也就是源代码(.java)文件编译成字节码文件(.class)

3. 类加载的过程

类加载的过程大致分为以下几步:

  1. 加载
  2. 加载
    • 验证
    • 准备
    • 解析
  3. 初始化

加载:加载是将类的字节码文件加载到内存中的过程。
验证:验证是确保类的字节码符合Java虚拟机规范的过程。
准备: 给类中的静态变量分配内存空间
解析: 初始化字符串常量,把符号引用(占位符)替换成直接引用(内存地址)
初始化:初始化是执行类的初始化代码的过程。

什么时候进行类加载呢?

使用到一个类的时候,就触发类加载(类不一定是程序已启动就加载了,第一次使用时才加载),有点类似于"懒汉模式"

4. 双亲委派

双亲委派是Java类加载器的一种机制,用于保证类的加载安全和避免重复加载。

在讲双亲委派之前,先来了解类加载器

Java类加载器主要有以下几种类型:

  1. 启动类加载器(Bootstrap Class Loader):它是JVM的内置类加载器,负责加载Java标准库中的类
  2. 扩展类加载器(Extension Class Loader):它是Java平台提供的标准类加载器之一,用于加载Java扩展库(如javax包中的类)和Java虚拟机的扩展部分。
  3. 应用程序类加载器(Application Class Loader):也称为系统类加载器(System Class Loader),它是加载应用程序类的默认加载器。应用程序类加载器加载应用程序类路径上的类,即开发人员编写的类和第三方类库。

上述三个类加载器存在父子关系,启动类加载器是扩展类加载器的父类,扩展类加载器是应用程序类加载器的父类

进入类加载的时候,输入的内容是全限定类名,加载的时候从Application Class Loder开始. 即当一个类加载器收到加载类的请求时,它会先委派给父类加载器,只有在父加载器找不到该类的情况下,才会自己加载。如果一直找到最下面的"Application Class Loder"也没有找到,就会抛出一个"类没找到"这样的异常

按照这个顺序的加载最大的好处就是如果子定义的类和Java标准库的类冲突了,此时仍然保留类加载可以加载到标准库中的类

5. GC垃圾回收

GC垃圾回收是Java虚拟机(JVM)自动管理内存的过程。它通过自动识别和回收不再使用的对象,释放内存资源,并提供了内存管理的机制,使开发人员无需手动进行内存释放。

在学习C语言时,有个关键字叫 malloc(动态内存申请),它的内存释放时机是不确定的,需要使用的free进行释放.如果不进行free,这个内存就会一直持续到程序结束. 如果忘记释放,就可能会造成"内存泄漏"

而在Java中,当对象不再被引用时,它们变成了垃圾。垃圾回收器负责扫描程序的内存,找出这些不再被引用的对象,并将它们的内存空间回收,以便后续的对象可以使用。

GC垃圾回收机制基本上可以把内存泄漏问题解决的差不多,但GC也并不是完美的,GC有个STW(stop the world)问题

STW指的是垃圾回收过程中,应用程序的执行被暂停停止的情况。在STW期间,所有的应用线程都会被挂起,直到垃圾回收完成。

STW问题可能会对应用程序的性能和响应时间产生影响,特别是在大型内存或高并发场景下。应用程序的执行会被中断,可能导致暂停时间较长,从而影响系统的实时性和用户体验。

GC垃圾回收主要会受到是哪些内容呢? 答案是,且GC中回收内存,不是以"字节"为单位进行回收的,而是以"对象"为单位回收.

GC怎么判断某个对象是否是垃圾呢?

假设有一个对象,如果已经没有任何引用能够指向它了,说明对象自然就无法再被使用了

两种典型的判定对象是否存在引用的方法:

  1. 引用计数(不是JVM采取的办法)
    • 引用计数的优点: 简单,容易实现,执行效率比较高
    • 引用计数的却嗲: 空间利用率低,可能会出现循环引用的情况
  2. 可达性分析(JVM采取的办法)

在Java中,GC通过根对象作为起点,查找所有与根对象直接或间接相连的对象,这些对象被称为可达对象,它们是程序中仍然被引用的对象。与根对象没有引用链相连的对象被认为是不可达的,它们将被垃圾回收器标记为可回收的对象。

6. JVM的回收方式

共有以下几种方式:

  1. 标记清除: 标记-清除是最基本的垃圾回收算法。它分为两个阶段:标记阶段和清除阶段。在标记阶段,垃圾回收器标记所有可达的对象,将其标记为存活对象。在清除阶段,垃圾回收器清除未被标记的对象,释放它们占用的内存空间。
  2. 复制算法:将内存分为两个区域,一次只使用其中一个区域。在对象存活后,将其复制到未使用的区域中,然后清除旧区域中的所有对象。复制算法适用于对象存活率较低的场景,因为需要较大的内存空间来进行复制。
  3. 标记整理: 标记-整理算法结合了标记-清除和复制算法的特点。它首先标记所有可达对象,然后将存活对象向一端移动,并清除未移动的内存空间。标记-整理算法适用于对象存活率较高的场景。

7. 分代回收

上述三种方式,虽然都可以实现GC回收,但都会存在一些问题. 因此在使用时,就需要根据不同的场景,采取不同的策略.

所以有引入的一个新的垃圾回收机制-"分代回收"

分代回收:分代算法是基于对象生命周期的假设,将内存分为不同的代,一般分为新生代和老年代。新生代中的对象生命周期短暂,采用复制算法进行回收;而老年代中的对象生命周期较长,采用标记-清除或标记-整理算法进行回收。分代算法适用于大部分应用程序,因为对象的生命周期通常是不同的。

新生代的对象被GC扫描的概率低,老年代的对象被GC的扫描率低. 新生代只有熬过多次GC的扫描,没有被回收,才会进入老年代

注: 如果对象是一个特别大的对象,会直接进入老年代

文章到这就结束了,感谢您的观看!

相关推荐
weixin_4624462341 分钟前
Python 使用 openpyxl 从 URL 读取 Excel 并获取 Sheet 及单元格样式信息
python·excel·openpyxl
一嘴一个橘子1 小时前
mybatis - 动态语句、批量注册mapper、分页插件
java
组合缺一1 小时前
Json Dom 怎么玩转?
java·json·dom·snack4
危险、1 小时前
一套提升 Spring Boot 项目的高并发、高可用能力的 Cursor 专用提示词
java·spring boot·提示词
kaico20181 小时前
JDK11新特性
java
钊兵1 小时前
java实现GeoJSON地理信息对经纬度点的匹配
java·开发语言
jiayong231 小时前
Tomcat性能优化面试题
java·性能优化·tomcat
毕设源码-钟学长1 小时前
【开题答辩全过程】以 基于Python的健康食谱规划系统的设计与实现为例,包含答辩的问题和答案
开发语言·python
秋刀鱼程序编程1 小时前
Java基础入门(五)----面向对象(上)
java·开发语言
纪莫2 小时前
技术面:MySQL篇(InnoDB的锁机制)
java·数据库·java面试⑧股