Java进阶---JVM
JVM概述
JVM作用:
负责将字节码翻译为机器码,管理运行时内存
JVM整体组成部分:
类加载系统(ClasLoader):负责将硬盘上的字节码文件加载到内存中
运行时数据区(RuntimeData Area):负责存储运行时各种数据
执行引擎(Execution Engine):负责将字节码转为机器码
本地方法接口(Native Interface):负责调用本地方法(非Java的方法)
垃圾回收(重点)
类加载系统
作用
负责将硬盘上的字节码文件加载到内存中(运行时数据区中)
类什么时候被加载
1.在一个类写一个main方法,运行main方法
2.new某个类对象时
3.使用类中的静态成员
4.使用反射机制时
public class Hello {final static int num = 10;static int num1= 10;/*静态代码块在类被加载时自动执行,目前可以看做一个类只被加载一次*/static {System.out.println("类被加载了");}public static void main(String[] args) {System.out.println("111111111");}
}public class TestHello {public static void main(String[] args) throws ClassNotFoundException {//new Hello();//System.out.println(Hello.num);// Class.forName("com.ffyc.javapro.jvm.classloader.Hello");/*创建的是数组对象,数组是Hello类型*/Hello [] hellos = new Hello[10];//只是访问类中的静态常量,类是不加载的,直接返回静态常量值即可System.out.println(Hello.num);//System.out.println(Hello.num1);}
}
类加载的过程(了解)
加载阶段:以字节流形式读取文件
连接阶段:验证 准备 解析
初始化阶段:主要为静态成员变量初始化赋值
类加载器
类加载器就是负责加载类的实践者
不同的类,是由不同的类加载器加载的
类加载器的分类:
启动类加载器(引导类加载器),不是用Java语言写的,而是用C/C++写的,负责加载虚拟机核心的类库
扩展类加载器,是用Java语言写的,负责加载jre/lib/ext目录下的类
应用程序类加载器,是用Java语言写的,负责加载程序员写的项目中的类(target/class)
双亲委派机制
当收到类加载任务时,首先委派给上级的类加载器加载,如果上级类加载器还有父级,依次递归,直到最顶级的启动类加载器,当父级类加载器找到类时,成功返回。
如果找不到,就要委派给子类加载器,如果子类加载器找到后,成功返回。
如果均未找到,那么就输出ClassNotFoundException
为什么设计双亲委派机制
为了安全,避免了自己定义的类,替换了系统中的核心类
例如:自己创建java.lang.String,结果还是加载的系统中的String类
如何打破双亲委派机制
可以自定义类加载器
写一个类 继承ClassLoader类,
重写findClass();
自己用流将字节码读入
Class<?> clazz = defineClass(null, bytes, 0, bytes.length);
Object o = clazz.newInstance();//反射机制创建对象//com.ffyc.javapro.jvm.classloader.MyClassLoader@1b6d3586
System.out.println(clazz.getClassLoader());
运行时数据区
当类加载系统把类信息加载到内存后,存储到运行时数据区
运行时数据区,根据不同的功能可以分为5个部分:
程序计数器
作用:程序计数器用来记录线程执行的指令集的位置,因为线程在执行时cpu要进行切换执行,需要记录线程执行的位置
特点:
1.是运行时数据区中空间最小的,运行速度最快的区域
2.每个线程都有一个属于自己的程序计数器,是线程私有的,程序计数器生命周期与线程生命周期相同
3.程序计数器是运行时数据区中唯一一个不会有内存异常情况的区域
虚拟机栈
虚拟栈是运行单位,管理程序如何执行,调用一个方法,方法入栈执行,运行结束后,出栈.
虚拟机栈主要用来运行java语言写的方法.
特点:
线程私有的,每个线程中调用的方法都在线程对应的虚拟机栈中执行.
栈中存储局部变量
虚拟栈中不存在垃圾回收
虚拟机栈中会存在内存溢出问题(递归调用太深)
Exception in thread "main" java.lang.StackOverflowError 栈溢出错误
A线程中的方法不能调用B线程中的方法
先进后出
public void test(){int a = 10;//局部变量int b= 20;String s = new String(); //s是引用类型,保存的是对象地址
}
当一个方法被调用后,被压入到虚拟机栈中称为一个栈帧,
栈帧内部结构:
局部变量表(存储局部变量的区域)
操作数栈(操作数栈就是用来计算的区域)
例如
int a= 10,int b=20; //a和b存储在局部变量表中
int c = a+b ;//计算时,把a和b从局部变量表加载到操作数栈运算,把 运算结果赋给c,把c写回到局部变量表
方法返回地址: 记录方法调用的位置,方法执行完成后要回到自己开的位置
本地方法栈
本地方法: 在java程序中,不是用java语言实现的方法, 由底层操作系统提供
使用 native关键修饰的方法,没有方法体
因为java语言属于上层语言(开发上层应用程序),没有权限与底层硬件进行交互(如读取内存数据,读取硬盘数据),
本地方法栈用来执行本地方法的,当程序中调用了本地方法,那么被加载到本地方法栈中运行.
特点:
线程私有的,每个线程都有属于自己的本地方法栈
本地方法栈也会出现内存溢出情况
本地方法栈中不会出现垃圾回收
堆
概述
作用: 堆空间是用来存储java中创建的对象的
特点: 堆空间是运行时数据区中最大的一块内存空间,
还可以根据需要通过参数设置大小: -Xms:10m(堆起始大小) -Xmx:30m(堆最大内大小
堆空间是所有线程共享的.
堆空间会出现内存溢出情况的.
堆空间是垃圾回收的重点区域.
堆内存区域划分
新生代(区):
伊甸园区
幸存者0(from)
幸存者1(to)
老年代(区):
为什么要分区(代)
根据对象的存活周期,对象的大小放在不同的区域,不同的区域可以采用不同的垃圾回收算法.
会频繁的回收新生代, 相对较少回收老年代.
可以对回收算法扬长避短.
对象创建内存分配过程
1.新创建的对象都存储在伊甸园区(比较大的对象,可以直接分配到老年代)
2.当下次垃圾回收到来时,把伊甸园区存活的对象移动到幸存者0区,清空伊甸园区
3.当下次垃圾回收时,把伊甸园区中存活的对象和幸存者0区的存活对象移动到幸存者1区,清空伊甸园区和幸存者0区.
4.当一个对象经历过最大上限15次垃圾回收后,依然存活,那么将此对象移动到老年代
堆空间参数
涉及JVM调优面试题
根据实际的需要。来调整JVM中原有的一些参数,如堆的初始化大小,分代年龄
官网地址: https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
-XX:+PrintFlagsInitial查看所有参数的默认初始值
-Xms:初始堆空间内存
-Xmx:最大堆空间内存
-Xmn:设置新生代的大小
-XX:MaxTenuringTreshold:设置新生代垃圾的最大年龄
-XX:+PrintGCDetails 输出详细的 GC处理日志
方法区
概述
方法区主要存放类信息(属性,方法,静态常量...)和编译器编译后的代码,
也是线程共享的区域,
方法的大小也是可以设置的,方法区的大小决定可以加载多少的类,
方法区也是有可能出现内存溢出的。
方法区大小设置
Java 方法区的大小不必是固定的,JVM可以根据应用的需要动态调整.
元数据区大小可以使用参数-XX:MetaspaceSize指定
方法区的垃圾回收
方法区也是有垃圾回收的,方法区的垃圾回收主要回收的是类信息。
类信息回收条件是比较苛刻的:
1.该类所创建的对象已经不再使用,并且被回收了
2.该类的Class对象也不再被使用了
3.加载该类的类加载器也被回收了
线程共享:堆,方法
线程私有的:程序计数器,虚拟机栈,本地方法栈
会出现内存溢出:堆,方法,虚拟机栈,本地方法栈
会出现垃圾回收:堆,方法区
本地方法接口
虚拟机中负责调用本地方法的入口,本地方法运行在本地方法栈中。
什么是本地方法
被native修饰的方法,没有方法体,是操作系统提供的方法
为什么Java中要调用本地方法
Java属于上层应用开发语言,没有权限直接访问计算机硬件(硬盘,内存,外设(喇叭)),需要调用本地操作系统提供的方法。
执行引擎(黑盒)
执行引擎在虚拟机中主要负责将加载到虚拟机中的字节码 解释/翻译 为机器码
.java-----jdk编译--->.class 在开发阶段(前端编译)
.class-----执行引擎编译--->机器码 在运行阶段(后端编译)
什么是解释器?什么是JIT编译器?
解释器/解释执行--->sql,html,css,js,python解释执行 不需要整体编译,由解释器一行一行执行,
解释执行特点:速度慢,不需要花费时间编译
编译执行,先把代码整体进行编译,生成另一种文件格式,
编译执行特点:编译后执行快,但是编译需要花费一定的时间
jvm中的执行引擎在将字节码编译为机器码时,采用半解释,半编译机制。
开始时,可以先采用解释执行,立即投入到翻译工作中,
等到编译器编译完成后,采用编译执行
垃圾回收
Java语言特点
开源,跨平台,面向对象,自动垃圾回收,线程,网络...
概述
什么是垃圾?
一个对象没有被任何引用指向,这个对象就可以被回收,就称为垃圾对象,
垃圾对象如果不及时清理,导致新对象肯可能没有空间存储,进而导致内存溢出(内存不够用了)
早期垃圾回收
早期是手动的回收 C和C++
malloc()
free()
给程序员带来不便,如果忘记释放,造成内存泄漏(对象不再使用,但是还占用着内存)
现在的语言多数采取了自动垃圾回收,例如java
程序员只需要new对象申请内存,不需要自己去释放空间,解放了开发人员
应该关心哪些区域的回收?
重点是堆:频繁回收新生代,较少回收老年代
方法区
内存溢出与内存泄漏
内存溢出:内存空间不足以运行程序,会报出内存错误(out of memory OOM)Error
内存泄漏:一些对象已经不再被使用l,但是垃圾回收器却不能回收的对象,一直悄悄的占用着内存资源。
举例:提供close()方法关闭资源的对象
数据库连接对象,
网络Socket
IO读取文件的对象
垃圾回收相关算法
垃圾标记阶段算法
标记阶段的目的:将堆内存中的对象进行检查,检查对象有没有被引用指向。
标记阶段涉及两个算法:引用计数算法(现在的虚拟机已经不再使用了)
可达性分析算法
引用计数算法:
思想:在每个对象中设置一个字段用来记录引用的数量,有一个引用指向对象,计数器加一,一旦有引用断开,计数器减一;
优缺点:实现思路简单
计数器字段占用空间,加一,减一是需要开销的,
重点是不能解决循环引用问题,A.B.C三个对象之间相互关联引用,此时计数器都是1,但是可能与外界没有联系,外界不可能使用A.B.C这三个对象,垃圾回收器不能回收他们,造成内存泄漏问题。
Hello h1 = new Hello(); 引用计数器0
Hello h2 = h1;
h1 = null;
h2 = null;
可达性分析算法(根搜索算法,追踪性分析算法)
思想:从一些活跃对象开始进行搜索,只要跟根对象有联系的对象,就不是垃圾对象,
与根对象没有任何联系的,即使对象之间存在引用关系,也可以判定为垃圾对象。
解决了引用计数算法中的循环引用问题。
哪些对象可以作为根对象:
1.虚拟机中引用的对象 运行中的方法中引用的对象
2.类中的一些静态成员变量
3.与同步锁有关的对象
4.虚拟机内部的一些类Class类,异常类,类加载器
final finally{ } finalize()
Object类中finalize()
public class Demo{protected void finalize() throws Throwable { Demo a = this;}
}
finalize()在对象被判定为垃圾后,在对象被真正回收之前由虚拟机自动调用,
在finalize()中执行一些最后要执行的功能,
finalize()只被执行一次
由于finalize()存在,对象可以分为3种状态:
可触及的:有引用指向的对象
可复活的:已经被判定为垃圾对象,但是fianlize()方法还没执行过,有可能在finalize()中复活
不可触及的:fianlize()已经被执行过了,并且又判定为垃圾了
垃圾回收阶段算法
标记-复制算法
将内存分为两块,把正在使用中的内存块的存活对象,复制到另一块内存中,从内存块的开始位置摆放,然后清除正在使用的内存块.
对象会被移动, 适合存活对象少,垃圾对象多的场景, 适合新生代的回收.
标记-清除算法
不移动存活对象的,将垃圾对象中的地址记录在一个空闲列表,有新对象到来时,可以把新对象分配到空闲列表中的内存地址上,覆盖垃圾对象.
适合老年代回收,因为存活多且大,不需要移动对象.
标记-压缩算法
将存活对象会压缩到内存的一端,重新排列,将边界外的空间进行清理,以减少内存碎片.
也是适用于老年代
垃圾回收器
标记阶段算法和回收阶段的算法都是方法论,垃圾回收器是真正回收的实践者.
不同的jdk版本中提供不同的垃圾回收器, 不同的版本的jdk中可以由不同开发商实现垃圾回收器.
垃圾收集器分类
从线程数量分: 单线程垃圾收集器,只有一个线程进行垃圾回收
多线程垃圾收集器,有多个线程同时进行垃圾回收
从工作模式分: 独占式垃圾收集器, 当垃圾收集线程执行时,其他程序线程会暂停执行
并发式垃圾收集器, 当垃圾收集线程执行时,可以允许其他程序线程同时执行
从回收的内存空间分: 新生代垃圾收集器
老年代垃圾收集器
jdk8中内置的垃圾回收器
Serial,Serial Old,
ParNew,Parallel Scavenge,Parallel Old,
CMS,
G1
重点了解2款垃圾收集器
CMS(Concurrent Mark Sweep,并发标记清除),这款垃圾收集器首创了垃圾回收线程和其他程序线程同时执行.
初始标记: 垃圾回收线程独占的
并发标记: 用户程序线程和垃圾回收线程同时执行的
重新标记: 垃圾回收线程独占的
并发清理: 用户程序线程和垃圾回收线程同时执行的
重置线程: 用户程序线程和垃圾回收线程同时执行的
相关文章:

Java进阶---JVM
JVM概述 JVM作用: 负责将字节码翻译为机器码,管理运行时内存 JVM整体组成部分: 类加载系统(ClasLoader):负责将硬盘上的字节码文件加载到内存中 运行时数据区(RuntimeData Area):负责存储运行时各种数据 执行引擎(Ex…...
鸿蒙OSUniApp离线优先数据同步实战:打造无缝衔接的鸿蒙应用体验#三方框架 #Uniapp
UniApp离线优先数据同步实战:打造无缝衔接的鸿蒙应用体验 最近在开发一个面向鸿蒙生态的UniApp应用时,遇到了一个有趣的挑战:如何在网络不稳定的情况下保证数据的实时性和可用性。经过一番探索和实践,我们最终实现了一套行之有效…...
地震资料裂缝定量识别——学习计划
学习计划 地震资料裂缝定量识别——理解常规采集地震裂缝识别方法纵波各向异性方法蚁群算法相干体及倾角检测方法叠后地震融合属性方法裂缝边缘检测方法 非常规采集地震裂缝识别方法P-S 转换波方法垂直地震剖面方法 学习计划 地震资料裂缝定量识别——理解 地震资料裂缝识别&a…...

C++ 检查一条线是否与圆接触或相交(Check if a line touches or intersects a circle)
给定一个圆的圆心坐标、半径 > 1 的圆心坐标以及一条直线的方程。任务是检查给定的直线是否与圆相交。有三种可能性: 1、线与圆相交。 2、线与圆相切。 3、线在圆外。 注意:直线的一般方程是 a*x b*y c 0,因此输入中只给出常数 a、b、…...
23. Merge k Sorted Lists
目录 题目描述 方法一、k-1次两两合并 方法二、分治法合并 方法三、使用优先队列 题目描述 23. Merge k Sorted Lists 方法一、k-1次两两合并 选第一个链表作为结果链表,每次将后面未合并的链表合并到结果链表中,经过k-1次合并,即可得到…...
每日算法刷题计划Day20 6.2:leetcode二分答案3道题,用时1h20min
9.3048.标记所有下标的最早秒数(中等) 3048. 标记所有下标的最早秒数 I - 力扣(LeetCode) 思想 1.给你两个下标从 1 开始的整数数组 nums 和 changeIndices ,数组的长度分别为 n 和 m 。 一开始,nums 中所有下标都是未标记的&a…...
Spring Security安全实践指南
安全性的核心价值 用户视角的数据敏感性认知 从终端用户角度出发,每个应用程序都涉及不同级别的数据敏感度。以电子邮件服务与网上银行为例:前者内容泄露可能仅造成隐私困扰,而后者账户若被操控将直接导致财产损失。这种差异体现了安全防护需要分级实施的基本原则: // 伪…...

Unity + HybirdCLR热更新 入门篇
官方文档 HybridCLR | HybridCLRhttps://hybridclr.doc.code-philosophy.com/docs/intro 什么是HybirdCLR? HybridCLR(原名 huatuo)是一个专为 Unity 项目设计的C#热更新解决方案,它通过扩展 IL2CPP 运行时,使其支持动态加载和…...
QuickBASIC QB64 支持 64 位系统和跨平台Linux/MAC OS
QuickBASIC 的现代继任者 QB64 已发展成为一个功能强大的开源项目,支持 64 位系统和跨平台开发。以下是详细介绍: 项目首页 - QB64pe:The QB64 Phoenix Edition Repository - GitCode https://gitcode.com/gh_mirrors/qb/QB64pe 1. QB64 概述 官网&am…...

ElasticSearch迁移至openGauss
Elasticsearch 作为一种高效的全文搜索引擎,广泛应用于实时搜索、日志分析等场景。而 openGauss,作为一款企业级关系型数据库,强调事务处理与数据一致性。那么,当这两者的应用场景和技术架构发生交集时,如何实现它们之…...

【C语言极简自学笔记】项目开发——扫雷游戏
一、项目概述 1.项目背景 扫雷是一款经典的益智游戏,由于它简单而富有挑战性的玩法深受人们喜爱。在 C 语言学习过程中,开发扫雷游戏是一个非常合适的实践项目,它能够综合运用 C 语言的多种基础知识,如数组、函数、循环、条件判…...
Global Security Markets 第5章知识点总结
一、章节核心内容概述 《Global Securities Markets》第五章聚焦全球主要证券交易所、关联存管机构及跨境交易实务,重点解析“乘客市场(Passenger Markets)”概念与合规风险,同时涵盖交易费用、监管规则等实操要点。考虑到市场的…...
电子电路:4017计数器工作原理解析
4017是CMOS十进制计数器/分频器,它属于CD4000系列,工作电压范围比较宽,可能3V到15V。我记得它有10个译码输出端,每个输出端依次在高电平和低电平之间循环,可能用于时序控制或者LED显示什么的。 4017内部应该由计数器和译码器两部分组成。计数器部分可能是一个约翰逊计数器…...
Vim 中设置插入模式下输入中文
在 Vim 中设置插入模式下输入中文需要配置输入法切换和 Vim 的相关设置。以下是详细步骤: 1. 确保系统已安装中文输入法 在 Linux 系统中,常用的中文输入法有: IBus(推荐):支持拼音、五笔等Fcitx…...
GitHub 趋势日报 (2025年05月31日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 1153 prompt-eng-interactive-tutorial 509 BillionMail 435 ai-agents-for-begin…...

Maven概述,搭建,使用
一.Maven概述 Maven是Apache软件基金会的一个开源项目,是一个有优秀的项目构建(创建)工具,它用来帮助开发者管理项目中的jar,以及jar之间的依赖关系,完成项目的编译,测试,打包和发布等工作. 我在当前学习阶段遇到过的jar文件: MySQL官方提供的JDBC驱动文件,通常命名为mysql-…...
基于大模型的数据库MCP Server设计与实现
基于大模型的数据库MCP Server设计与实现 引言 随着大语言模型(LLM, Large Language Model)能力的不断提升,AI Agent(智能体)正在从简单的对话问答,向更复杂的自动化任务执行和业务流程管理演进。在企业和开发者的实际需求中,数据库操作是最常见、最核心的场景之一。如…...
【前端】macOS 的 Gatekeeper 安全机制阻止你加载 bcrypt_lib.node 文件 如何解决
这个弹窗是 macOS 的 Gatekeeper 安全机制阻止你加载 bcrypt_lib.node 文件,因为它不是 Apple 签名的文件。 你想 “忽视” 它,其实是让系统允许这个 .node 原生模块运行,解决方式如下: sudo xattr -d com.apple.quarantine nod…...

Unity 环境搭建
Unity是一款游戏引擎,可用于开发各种类型的游戏和交互式应用程序。它由Unity Technologies开发,并在多个平台上运行,包括Windows、macOS、Linux、iOS、Android和WebGL。Unity也支持虚拟现实(VR)和增强现实(AR)技术,允许用户构建逼…...
【入门】【练9.3】 加四密码
| 时间限制:C/C 1000MS,其他语言 2000MS 内存限制:C/C 64MB,其他语言 128MB 难度:中等 分数:100 OI排行榜得分:12(0.1*分数2*难度) 出题人:root | 描述 要将 China…...

使用 SASS 与 CSS Grid 实现鼠标悬停动态布局变换效果
最终效果概述 页面为 3x3 的彩色格子网格;当鼠标悬停任意格子,所在的行和列被放大;使用纯 CSS 实现,无需 JavaScript;利用 SASS 的模块能力大幅减少冗余代码。 HTML 结构 我们使用非常基础的结构,9 个 .i…...
Node.js 全栈开发方向常见面试题
Node.js 全栈开发”方向的面试题**,这类岗位通常包括: 后端:Node.js(Express/Nest)、数据库、REST API、安全、部署等 前端:React/Vue(部分可能含 Next.js)、API 调用、状态管理等 …...

Spring如何实现组件扫描与@Component注解原理
Spring如何实现组件扫描与Component注解原理 注解配置与包扫描的实现机制一、概述:什么是注解配置与包扫描?二、处理流程概览三、注解定义ComponentScope 四、核心代码结构1. ClassPathScanningCandidateComponentProvider2. ClassPathBeanDefinitionSca…...
历年四川大学计算机保研上机真题
2025四川大学计算机保研上机真题 2024四川大学计算机保研上机真题 2023四川大学计算机保研上机真题 在线测评链接:https://pgcode.cn/school 分数求和 题目描述 有一分数序列: 2 / 1 2/1 2/1, 3 / 2 3/2 3/2, 5 / 3 5/3 5/3, 8 / 5 8/5 8/5, 13 /…...
gcc符号表生成机制
符号表生成机制 我们以C语言的编译链接过程为例,详细讲解符号表(Symbol Table)的流程,涵盖编译和链接两个阶段。理解符号表是理解链接器如何解决符号引用(如函数、变量)的关键。 符号表分为两种ÿ…...

达梦数据库 Windows 系统安装教程
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…...
unix/linux source 命令,其基本概念、定义、性质、定理
从计算机科学的角度,特别是形式语言、操作系统和编程语言设计的角度来看,source (或 .) 命令虽然看似简单,但其背后也蕴含着一些核心的概念、定义、性质和可以类比的“定理”(或者说,更准确地是“设计原则”或“行为模式”)。 让我们尝试从一个更理论和结构化的视角来剖…...

【Java EE初阶】计算机是如何⼯作的
计算机是如何⼯作的 计算机发展史冯诺依曼体系(Von Neumann Architecture)CPU指令(Instruction)CPU 是如何执行指令的(重点) 操作系统(Operating System)进程(process) 进程 PCB 中的…...

RAG理论基础总结
目录 概念 流程 文档收集和切割 读取文档 转换文档 写入文档 向量转换和存储 搜索请求构建 向量存储工作原理 向量数据库 文档过滤和检索 检索前 检索 检索后 查询增强和关联 QuestionAnswerAdvisor查询增强 高级RAG架构 自纠错 RAG(C-RAG…...

列表推导式(Python)
[表达式 for 变量 in 列表] 注意:in后面不仅可以放列表,还可以放range ()可迭代对象 [表达式 for 变量 in 列表 if 条件]...