Java进阶---JVM

news2025/6/5 0:11:53

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,并发标记清除),这款垃圾收集器首创了垃圾回收线程和其他程序线程同时执行.

初始标记: 垃圾回收线程独占的

并发标记: 用户程序线程和垃圾回收线程同时执行的

重新标记: 垃圾回收线程独占的

并发清理: 用户程序线程和垃圾回收线程同时执行的

重置线程: 用户程序线程和垃圾回收线程同时执行的

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

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

相关文章

C++ 检查一条线是否与圆接触或相交(Check if a line touches or intersects a circle)

给定一个圆的圆心坐标、半径 > 1 的圆心坐标以及一条直线的方程。任务是检查给定的直线是否与圆相交。有三种可能性&#xff1a; 1、线与圆相交。 2、线与圆相切。 3、线在圆外。 注意&#xff1a;直线的一般方程是 a*x b*y c 0&#xff0c;因此输入中只给出常数 a、b、…

23. Merge k Sorted Lists

目录 题目描述 方法一、k-1次两两合并 方法二、分治法合并 方法三、使用优先队列 题目描述 23. Merge k Sorted Lists 方法一、k-1次两两合并 选第一个链表作为结果链表&#xff0c;每次将后面未合并的链表合并到结果链表中&#xff0c;经过k-1次合并&#xff0c;即可得到…

Unity + HybirdCLR热更新 入门篇

官方文档 HybridCLR | HybridCLRhttps://hybridclr.doc.code-philosophy.com/docs/intro 什么是HybirdCLR? HybridCLR&#xff08;原名 huatuo&#xff09;是一个专为 Unity 项目设计的C#热更新解决方案&#xff0c;它通过扩展 IL2CPP 运行时&#xff0c;使其支持动态加载和…

ElasticSearch迁移至openGauss

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

【C语言极简自学笔记】项目开发——扫雷游戏

一、项目概述 1.项目背景 扫雷是一款经典的益智游戏&#xff0c;由于它简单而富有挑战性的玩法深受人们喜爱。在 C 语言学习过程中&#xff0c;开发扫雷游戏是一个非常合适的实践项目&#xff0c;它能够综合运用 C 语言的多种基础知识&#xff0c;如数组、函数、循环、条件判…

Maven概述,搭建,使用

一.Maven概述 Maven是Apache软件基金会的一个开源项目,是一个有优秀的项目构建(创建)工具,它用来帮助开发者管理项目中的jar,以及jar之间的依赖关系,完成项目的编译,测试,打包和发布等工作. 我在当前学习阶段遇到过的jar文件: MySQL官方提供的JDBC驱动文件,通常命名为mysql-…

Unity 环境搭建

Unity是一款游戏引擎&#xff0c;可用于开发各种类型的游戏和交互式应用程序。它由Unity Technologies开发&#xff0c;并在多个平台上运行&#xff0c;包括Windows、macOS、Linux、iOS、Android和WebGL。Unity也支持虚拟现实(VR)和增强现实(AR)技术&#xff0c;允许用户构建逼…

【入门】【练9.3】 加四密码

| 时间限制&#xff1a;C/C 1000MS&#xff0c;其他语言 2000MS 内存限制&#xff1a;C/C 64MB&#xff0c;其他语言 128MB 难度&#xff1a;中等 分数&#xff1a;100 OI排行榜得分&#xff1a;12(0.1*分数2*难度) 出题人&#xff1a;root | 描述 要将 China…

使用 SASS 与 CSS Grid 实现鼠标悬停动态布局变换效果

最终效果概述 页面为 3x3 的彩色格子网格&#xff1b;当鼠标悬停任意格子&#xff0c;所在的行和列被放大&#xff1b;使用纯 CSS 实现&#xff0c;无需 JavaScript&#xff1b;利用 SASS 的模块能力大幅减少冗余代码。 HTML 结构 我们使用非常基础的结构&#xff0c;9 个 .i…

Spring如何实现组件扫描与@Component注解原理

Spring如何实现组件扫描与Component注解原理 注解配置与包扫描的实现机制一、概述&#xff1a;什么是注解配置与包扫描&#xff1f;二、处理流程概览三、注解定义ComponentScope 四、核心代码结构1. ClassPathScanningCandidateComponentProvider2. ClassPathBeanDefinitionSca…

达梦数据库 Windows 系统安装教程

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…

【Java EE初阶】计算机是如何⼯作的

计算机是如何⼯作的 计算机发展史冯诺依曼体系&#xff08;Von Neumann Architecture&#xff09;CPU指令&#xff08;Instruction&#xff09;CPU 是如何执行指令的&#xff08;重点&#xff09; 操作系统&#xff08;Operating System&#xff09;进程(process) 进程 PCB 中的…

RAG理论基础总结

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

列表推导式(Python)

[表达式 for 变量 in 列表] 注意&#xff1a;in后面不仅可以放列表&#xff0c;还可以放range ()可迭代对象 [表达式 for 变量 in 列表 if 条件]

一天搞懂深度学习--李宏毅教程笔记

目录 1. Introduction of Deep Learning1.1. Neural Network - A Set of Function1.2. Learning Target - Define the goodness of a function1.3. Learn! - Pick the best functionLocal minimaBackpropagation 2. Tips for Training Deep Neural Network3. Variant of Neural…

python打卡训练营打卡记录day43

复习日 作业&#xff1a; kaggle找到一个图像数据集&#xff0c;用cnn网络进行训练并且用grad-cam做可视化 进阶&#xff1a;并拆分成多个文件 数据集来源&#xff1a;Flowers Recognition 选择该数据集原因&#xff1a; 中等规模&#xff1a;4242张图片 - 训练快速但足够展示效…

【QT控件】QWidget 常用核心属性介绍 -- 万字详解

目录 一、控件概述 二、QWidget 核心属性 2.1 核心属性概览 2.2 enabled ​编辑 2.3 geometry 2.4 windowTitle 2.5 windowIcon 使用qrc文件管理资源 2.6 windowOpacity 2.7 cursor 2.8 font ​编辑 2.9 toolTip 2.10 focusPolicy 2.11 styleSheet QT专栏&…

uniapp-商城-77-shop(8.2-商品列表,地址信息添加,级联选择器picker)

地址信息,在我们支付订单上有这样一个接口,就是物流方式,一个自提,我们就显示商家地址。一个是外送,就是用户自己填写的地址。 这里先说说用户的地址添加。需要使用到的一些方式方法,主要有关于地址选择器,就是uni-data-picker级联选择。 该文介绍了电商应用中地址信息处…

【第16届蓝桥杯 | 软件赛】CB组省赛第二场

个人主页&#xff1a;Guiat 归属专栏&#xff1a;算法竞赛 文章目录 A. 密密摆放&#xff08;5分填空题&#xff09;B. 脉冲强度之和&#xff08;5分填空题&#xff09;C. 25 之和D. 旗帜E. 数列差分F. 树上寻宝G. 翻转硬币H. 破解信息 正文 总共8道题。 A. 密密摆放&#xff0…

AR/MR实时光照阴影开发教程

一、效果演示 1、PICO4 Ultra MR 发光的球 2、AR实时光照 二、实现原理 PICO4 Ultra MR开发时&#xff0c;通过空间网格能力扫描周围环境&#xff0c;然后将扫描到的环境网格材质替换为一个透明材质并停止扫描&#xff1b;基于Google ARCore XR Plugin和ARFoundation进行安卓手…