Java虚拟机(JVM)

目录

  • 内存区域划分
    • 堆(Heap)
    • 方法区(Method Area)
    • 程序计数器(Program Counter Register)
    • 虚拟机栈(VM Stack)
    • 本地方法栈(Native Method Stack)
  • 类加载的过程
    • 类加载过程
    • 类加载器
    • 双亲委派模型
  • 垃圾回收机制
    • 1. 找出垃圾
    • 2. 释放垃圾的内存空间

JVM(Java虚拟机)是Java Virtual Machine的缩写,是一种可以执行Java字节码的虚拟机。它为Java应用程序提供了一个与平台无关的执行环境,使得Java程序只需编写一次,就可以在安装了JVM的任何系统上运行
本文主要介绍三个部分:JVM内存区域划分、类加载的过程、垃圾回收机制

内存区域划分

运行时数据区划分如下
在这里插入图片描述

堆(Heap)

堆是JVM中最大的一块内存区域,主要用于存储对象实例,new出来的对象变量都是存储在栈上。堆是所有线程共享的内存区域(只有一份),并且是垃圾回收器的主要工作区域。堆内存大概分为以下几个部分:

  • 新生代(Young Generation):大多数对象的生命周期都很短,因此年轻代被划分为三个部分:Eden区、Survivor0区(S0)、Survivor1区(S1)。对象通常在Eden区被创建,经过一次垃圾回收后,存活的对象会被移动到S0或S1区,每经过一次垃圾回收,存活的对象就会在S0和S1之间移动,直到晋升到老年代。
  • 老年代(Old Generation):在年轻代中经历了多次垃圾回收仍然存活的对象,以及一些大对象(如大数组),会被移动到老年代。老年代的垃圾回收频率较低,因为这里存放的都是生命周期较长的对象。
    在这里插入图片描述

方法区(Method Area)

方法区是所有线程共享的内存区域(只有一份),用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

程序计数器(Program Counter Register)

程序计数器是一块小的内存空间,它为每个线程私有。程序计数器保存了当前执行的字节码指令的地址(类似于咱们写代码时的行号)。在JVM中,字节码解释器通过改变程序计数器的值来控制执行流程。

程序计数器是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依靠这个计数器完成。

在这里插入图片描述

虚拟机栈(VM Stack)

虚拟机栈也是线程私有的内存区域,它的生命周期与线程相同。虚拟机栈用于存储局部变量表、操作栈、动态链接、方法出口等信息。每个方法在执行时都会创建一个栈帧(Stack Frame),用于存储局部变量和操作数栈,当方法执行结束时,栈帧会被销毁。

  • 局部变量表(Local Variables):存储方法中的局部变量。

  • 操作数栈(Operand Stack):用于存储计算过程中的中间数据。

  • 动态链接(Dynamic Linking):将符号引用转换为直接引用。

  • 方法出口(Method Exit):用于方法正常退出或异常退出时的清理工作。

本地方法栈(Native Method Stack)

本地方法栈与虚拟机栈类似,Java虚拟机栈是给JVM使用的,而本地方法栈是给本地方法使用的。

提问:下面变量(a、b、c、d、e、f)属于哪个内存区域?

class Test {private int a;private Test b = new Test();private static int c;private static Test d = new Test();public static void main(String[] args) {int e = 1;Test f = new Test();}
}

答:a、b属于堆,c、d属于方法区,e、f属于栈

变量属于哪个区和变量是否为内置类型无关

局部变量==>栈

成员变量==>堆

静态成员变量==>方法区

类加载的过程

JVM类加载是Java程序运行的基础,它涉及将类的.class文件从磁盘加载到内存中,并进行校验、链接和初始化等一系列步骤。

类加载过程

  1. 加载(Loading)

    • 类加载过程的第一步,JVM通过类的全限定名获取其定义这个类的二进制字节流(例如,从.class文件、JAR文件或者网络中获取)。

    • 将这个字节流所代表的静态存储结构转化为JVM内部运行时的数据结构。

    • 在内存中创建一个代表该类的java.lang.Class对象,这个对象将作为程序访问这个类的接口。

      简单来说就是:根据类名找到对应的.class文件,打开文件并读取内容。

  2. 验证(Verification)
    确保读取到的.class文件符合JVM规范,没有安全问题。包括文件格式验证、元数据验证、字节码验证和符号引用验证,确保类的信息是合法的,不会危害虚拟机的安全。

  3. 准备(Preparation)
    为类对象分配内存空间,根据读取到的.class文件内容,确定类对象所需要的空间大小,申请出对应大小的空间,并设置默认初始值(通常是0)。

  4. 解析(Resolution)
    将类、接口、字段和方法的符号引用转换为直接引用。符号引用就是类、字段、方法的全限定名,直接引用保存的是内存中的地址。

  5. 初始化(Initialization)
    执行类的静态初始化和静态变量的赋值操作,执行类中的静态代码块。

类加载器

JVM内置了几种主要的类加载器:

  1. 启动类加载器(Bootstrap ClassLoader)

    负责加载标准库中的类。

  2. 扩展类加载器(Extension ClassLoader)

    负责加载扩展类。

  3. 应用程序类加载器(Application ClassLoader)

    负责加载第三方库中的类、自己写的代码中的类。

双亲委派模型

双亲委派模型(Parent Delegation Model)是Java虚拟机(JVM)中的一种类加载机制。它的核心思想是,当一个类加载器收到类加载请求时,会先委托其父类加载器去完成这个请求,只有在父类加载器无法完成时,自己才会尝试去加载这个类。
在这里插入图片描述

双亲委派模型是类加载5个步骤中第一个步骤中的环节,

工作流程:通过得到的全限定名,

  1. 从Application ClassLoader开始进行加载,此时不会立刻扫描目录,而是把任务委派给Extension ClassLoader
  2. Extension ClassLoader拿到任务后,也不会立刻扫描目录,而是把任务委派给Bootstrap ClassLoader
  3. Bootstrap ClassLoader在目录中进行扫描加载对应的类,如果Bootstrap ClassLoader没找到对应的类,就把任务返回给Extension ClassLoader,如果找到了直接进行后续的类加载过程。类似的,如果Extension ClassLoader没找到,会继续吧任务返回给Application ClassLoader,如果Application ClassLoader找到了直接返回,如果Application ClassLoader没找到,就会抛出异常

类加载请求首先由父类加载器尝试完成,只有在父类加载器无法完成类加载时,才由子类加载器尝试自己去加载。

双亲委派模型机制就是为了防止用户自己定义的类和标准库的类名一样,把标准库的类覆盖掉。

垃圾回收机制

JVM的垃圾回收机制(Garbage Collection, GC)是Java内存管理的重要组成部分,主要目标是自动回收不再使用的对象,释放内存资源,避免内存泄漏和溢出。垃圾回收机制主要工作区域是堆。

GC是如何回收的?

1. 找出垃圾

方案1:给每个对象分配一个计数器,计数器记录的是当前有多少个变量引用了这个对象,每增加一个引用计数器就+1,每减少一个引用就-1。如果计数器为0,表示当前对象没有人引用它,说明这个对象就是垃圾。这个方案存在问题循环引用问题,并且会消耗额外的内存空间,JVM没有采用。
循环引用问题:

class Test {Test t = null;
}
//..........class Main {public static void main(String[] args) {Test a = new Test();Test b = new Test();a.t = b;b.t = a;a = null;b = null;}
}
//这两个对象引用计数器为0不能被释放,但是这两个对象又无法使用

方案2:可达性分析(JVM采用的方案)

JVM会从一组根对象(GCroot)开始,遍历所有可达对象(类似于二叉树、多叉树遍历)。如果某个对象不可通过根对象引用到达,JVM便会将其视为垃圾并回收。常见的GCroot:栈上的局部变量、方法区中的静态成员、常量池中引用指向的对象。

2. 释放垃圾的内存空间

有以下垃圾回收算法

标记-清除算法
先标记出所有存活的对象,然后清除未被标记的对象。这种方法简单,但会产生大量内存碎片(不是连续的空间),后续申请内存的时候可能申请不了(申请的空间一定是连续的)。

复制算法
将可用内存分为大小相等的两块,每次只使用一块,当一块用完,将存活的对象复制到另一块,然后清理已使用过的内存。这种方法解决了内存碎片问题,但代价是内存使用效率降低,复制成本比较大。

标记-整理算法
类似于顺序表删除中间元素的操作。先标记出存活的对象,然后让所有存活的对象向一端移动,之后清理端边界以外的内存区域。这种方法解决了内存碎片问题。这种方法的代价是移动存活对象的开销比较大

分代收集算法(JVM采取的方案)
根据对象存活周期的不同,将堆分为新生代和老年代。

在这里插入图片描述

  • 新生代(Young Generation):大多数对象的生命周期都很短,因此年轻代被划分为三个部分:Eden区、Survivor0区(S0)、Survivor1区(S1)。对象通常在Eden区被创建,经过一次垃圾回收后,存活的对象会被移动到S0或S1区,每经过一次垃圾回收,存活的对象就会在S0和S1之间移动,直到晋升到老年代。
  • 老年代(Old Generation):在年轻代中经历了多次垃圾回收仍然存活的对象,以及一些大对象(如大数组),会被移动到老年代。老年代的垃圾回收频率较低,因为这里存放的都是生命周期较长的对象。

新生代中的对象生命周期短,适合使用复制算法;老年代中的对象生命周期长,适合使用标记-整理算法。

垃圾回收器

现在常见的垃圾回收器有CMS、G1

CMS(Concurrent Mark-Sweep)垃圾回收器

减少STW(Stop The World),标记清除算法,并行处理大部分垃圾回收过程。可能产生内存碎片,老年代需要更大内存。

G1(Garbage First)垃圾回收器

面向服务端的低延迟垃圾回收器,将堆划分为多个区域,优先回收垃圾最多的区域。并行和并发执行,适合大内存应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/881506.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C++]使用纯opencv部署yolov11-seg实例分割onnx模型

【算法介绍】 在C中使用纯OpenCV部署YOLOv11-seg进行实例分割是一项具有挑战性的任务,因为YOLOv11通常是用PyTorch等深度学习框架实现的,而OpenCV本身并不直接支持加载和运行PyTorch模型。然而,可以通过一些间接的方法来实现这一目标&#x…

运维工具之ansible

Ansible 1.什么是ansible? ​ ansible是基于ssh架构的自动化运维工具,由python语言实现,通过ansible可以远程批量部署等。 2.部署前提 ​ 控制端需要安装ansible,被控制端要开启ssh服务,并允许远程登录,被管理主机需要安装py…

卸载PLSQL及标准卸载流程

目录 1. 卸载PLSQL2. 删除注册表3. 删除数据信息 1. 卸载PLSQL 等待进度条走完 2. 删除注册表 regedit 右击删除 3. 删除数据信息 由于AppData是隐藏文件,需要勾选隐藏的项目。 重启电脑,PLSQL就卸载成功了。

浏览器和客户端结合的erp系统,java控制浏览器操作自动登录,socket客户端通信进行表单赋值

java做一个toB的客户端操作系统,客户端和web的结合; 主要是使用java编写客户端代码,采用selenium控制浏览器,主要是用到selenium自动化测试的功能; javaEE 项目调用 selenium使用谷歌控件chromedriver.exe控制浏览器…

使用Java调用OpenAI API并解析响应:详细教程

使用Java调用OpenAI API并解析响应:详细教程 在现代应用程序中,API调用是一个非常常见的任务。本文将通过一个完整的示例,讲解如何使用Java调用OpenAI的ChatGPT API,并通过ObjectMapper处理JSON响应。本文的示例不仅适用于OpenAI…

网络参考模型

OSI七层网络参考模型 OSI模型仅作为参考,现实中并不用,OSI模型的目的是为了解决主机之间的网络通讯。 1. 物理层: 物理层将由比特(0和1)组成的数据用不同的媒介(电、光或其他形式的电磁波)传输…

黑马软件测试第一篇_测试理论

概念 使用技术手段验证软件功能是否符合需求 测试种类 功能测试 自动化测试 接口测试 性能测试 按测试阶段划分 单元测试:针对程序源码进行测试 集成测试:又称接口测试,针对模块之间访问地址进行测试 系统测试:对整个系统进行…

京东零售数据湖应用与实践

作者:陈洪健:京东零售大数据架构师,深耕大数据 10 年,2019 年加入京东,主要负责 OLAP 优化、大数据传输工具生态、流批一体、SRE 建设。 当前企业数据处理广泛采用 Lambda 架构。Lambda 架构的优点是保证了数据的完整性…

YOLO的相关改进机制

我的面包多平台有多种关于YOLO的改进,大家尽早关注,不迷路

【宽字节注入】

字符编码 url 编码 GBK编码 utf8 编码 宽字节注入 php中的转译函数 宽字节注入介绍 练习 正常输入没有回显: 没有回显 usernameadmin&passwordadmin 闭合单引号,依旧没有回显 usernameadmin and 11%23&passwordadmin利用宽字节尝试闭合,依旧…

查看SQL Server授权序列号通过SQL查询查看安装日志文件使用PowerShell查询

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

在Stable Diffusion WebUI中安装SadTalker插件时几种错误提示的处理方法

SD中的插件一般安装比较简单,但也有一些插件安装会比较难。比如我在安装SadTalker时,就遇到很多问题,一度放弃了,后来查了一些网上攻略,自己也反复查看日志,终于解决,不吐不快。 一、在Stable …

闪迪U盘误删的数据该怎么恢复呢?3个方法轻松解决

闪迪是一家全球知名的美国公司,也是全球最大的闪存数据存储卡产品供应商,其中,闪迪U盘作为其主要产品之一,因其便携性、大容量和高速传输能力而深受用户喜爱。然而,在平时存储重要数据的时候,会因为我们一系…

ElasticSearch备考 -- Update by query Reindex

一、题目 有个索引task,里面的文档长这样 现在需要添加一个字段all,这个字段的值是以下 a、b、c、d字段的值连在一起 二、思考 需要把四个字段拼接到一起,组成一个新的字段,这个就需要脚本, 这里有两种方案&#xff…

CSRF | GET 型 CSRF 漏洞攻击

关注这个漏洞的其他相关笔记:CSRF 漏洞 - 学习手册-CSDN博客 0x01:GET 型 CSRF 漏洞攻击 —— 理论篇 GET 型 CSRF 漏洞是指攻击者通过构造恶意的 HTTP GET 请求,利用用户的登录状态,在用户不知情的情况下,诱使浏览器…

Elasticsearch(二)集成Spring Boot 基本的API操作

目录 一、集成Spring Boot 1、创建项目 2、pom文件 查看springboot集成的依赖 3、增加es的config类 二、索引相关API 1、创建索引 2、获取索引,判断其是否存在 3、删除索引 三、文档相关API 1、添加文档 2、获取文档,判断是否存在 3、获取文档…

【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)

当前内容所在位置(可进入专栏查看其他译好的章节内容) 第一部分 D3.js 基础知识 第一章 D3.js 简介(已完结) 1.1 何为 D3.js?1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践(上)1.3 数据可…

深度学习:基于MindSpore实现ResNet50中药分拣

ResNet基本介绍 ResNet(Residual Network)是一种深度神经网络架构,由微软研究院的Kaiming He等人在2015年提出,并且在ILSVRC 2015竞赛中取得了很好的成绩。ResNet主要解决了随着网络深度增加而出现的退化问题,即当网络…

vulnhub-digitalworld.local DEVELOPMENT靶机

vulnhub:digitalworld.local: DEVELOPMENT ~ VulnHub 导入靶机,放在kali同网段,扫描 靶机在192.168.114.129,扫描端口 开了几个端口,8080端口有网页,访问 说是让访问html_pages 似乎把页面都写出来了&…

Unity网络开发基础 —— 实践小项目

概述 接Unity网络开发基础 导入基础知识中的代码 需求分析 手动写Handler类 手动书写消息池 using GamePlayer; using System; using System.Collections; using System.Collections.Generic; using UnityEngine;/// <summary> /// 消息池中 主要是用于 注册 ID和消息类…