了解JVM

一.JVM概述

1.JVM的作用

把字节码编译为机器码去执行,负责把字节码装载到虚拟机中

现在的 JVM 不仅可以执行 java 字节码文件,还可以执行其他语言编译后的字节码文件,是一个跨语言平台

2.JVM的组成部分

  1. 类加载器(ClassLoader)
  2. 运行时数据区(Runtime Data Area)
  3. 本地方法库(Execution Engine)
  4. 执行引擎(Native Interface)

程序在执行过程中需要把java文件转换为字节码文件,然后通过类加载器将文件存储在内存中的运行时数据区,而字节码文件是JVM的一套指令集规范,并不能直接交给底层系统去执行,因此需要特定命令的解析器执行引擎,将字节码编译为底层系统指令载交给cpu去执行,而这个过程中需要调用本地方法接口去实现整个程序的功能.

二.JVM类加载

1.类加载概述

类加载子系统负责从文件系统或网络中加载字节码文件,它只负责加载字节码文件,至于可不可以运行,则有执行引擎决定

2.类加载过程

2.1加载

使用流将硬盘上的字节码文件加载到内存中的运行时数据区的方法区,并生成对象的class对象

2.2链接

链接又分为三个步骤:

-验证:验证字节码格式是否正确,对字节码描述的信息进行语义分析,以保证其描述的信息符合java的语言规范

-准备:为类中的静态属性进行赋值(赋的值为0,在初始化阶段在进行赋值)

    static int a=123;   准备阶段a的值为0,在初始化阶段才赋值为123

-解析:将字节码中的逻辑引用替换为直接引用

逻辑引用:字节码中的逻辑符号

符号引用:内存地址

2.3初始化

为类的静态变量进行正确的赋值

类什么时候会初始化?

类只要被用到了都会被加载

1.new对象

2.加载子类时

3.反射机制

4.运行类中的main方法

5.使用了类的静态成员(类.静态变量  类.静态方法)

类什么时候不会被加载?

1.只访问了类的静态常量

2.创建的数组对象,只是作为类型存在

3.类加载器的分类

jvm角度来说,应该被分为俩类:

1.引导类加载器,使用 C/C++语言实现,嵌套在 JVM 内部.它用来加载 java 核心类库.

2.其他所有类加载器,这些类加载器全部由java语言实现,独立存在于jvm外部,并且全部继承自抽象类 java.lang.ClassLoader

站在java程序员的角度应该被分为三类:

1.引导类加载器

2.扩展类加载器,从 java.ext.dirs 系统属性所指定的目录中加载类库,或从 JDK 系统安装目录jre/lib/ext 子目录(扩展目录)下加载类库

3.应用程序类加载器,加载我们自己定义的类,用于加载用户类路径(classpath)上所有的类

4.双亲委派机制

java虚拟机对class文件采用的是按需加载的方式,也就是需要用到类时才把他的class文件加载到内存中生成class对象,在加载某个类的字节码文件时,jvm采用了双亲委派机制,即把请求交给父类处理,是一种任务委派机制.

工作原理:

如果一个类加载器收到了类加载请求,这个类加载器并不会自己先加载,而是将请求委托给父类的加载器去执行,如果父类加载器还存在父类,则继续向上委托,一次递归,直至得到顶层的启动类加载器,如果父类的加载器可以完成加载任务就成功返回,然后无法完成,子类才会自己尝试加载,如果均加载失败,就会抛出 ClassNotFoundException 异常

优点:安全,可以避免自己写的类替换java的核心类

如何打破双亲委派机制?

可以自定义类加载器

在 ClassLoader 类中涉及类加载的方法有两个,loadClass(String name), findClass(String name),这两个方法并没有被 final 修饰,也就表示其他子类可以重写.

三.运行时数据区

1.运行时数据区组成概述

2.程序计数器

用来记录下一条指令的地址,也就是即将要执行的指令,由执行引擎执行

特点:

它是一块很小的内存区域,也是运行速度最快的存储区域

在JVM规范中,每个线程都有一个计数器,是线程私有的,他的生命周期与线程一致
会记录当前线程正在执行的java程序的JVM指令地址
是唯一一个JVM规范中没有规定任何OutOfMemoryError情况的区域

3.虚拟机栈

Java 虚拟机栈(Java Virtual Machine Stack),早期也叫 Java 栈.每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个栈帧,对应着一次方法的调用.Java 虚拟机栈是线程私有的.主管 Java 程序的运行,它保存方法的局部变量(8种基本数据类型,对象的引用地址),部分结果,并参与方法的调用和返回.
栈的特点:
栈是一种快速有效的分配存储方式,访问速度仅次于程序计数器.
JVM 直接对 java 栈的操作只有两个:调用方法 入栈 .执行结束后 出栈 .
对于栈来说不存在垃圾回收问题
栈中会出现异常,当 线程请求的栈深度大于虚拟机所允许的深度时, 会出现StackOverflowError.
栈帧的内部结构:
局部变量表:局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。
操作数栈: 是用来对表达式求值,程序中的所有计算过程都是在借助于操作数栈来完成的。
方法返回地址:当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址.

4.堆

《Java 虚拟机规范》中对 Java 堆的描述是:所有的对象实例都应当在运行时分配在堆上.
堆也是 Java 内存管理的核心区域.是 JVM 管理的最大一块内存空间.
堆内存的大小是可以调节. 例如: -Xms:10m(堆起始大小) -Xmx:30m(堆最大内存大小)
所有的线程共享 Java 堆
堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除.
堆是 GC(Garbage Collection,垃圾收集器)执行垃圾回收的重点区域.

4.1堆内存的划分

在JDK1.8被分为新生代老年代,新生代又被分为伊甸园区幸存者区

为什么分区(分代)?

根据对象的存活概率进行分区,将存活时间长的放到老年代,减少扫描垃圾的时间和GC频率,针对分类进行不同的垃圾回收算法,对算法扬长避短。

对象创建内存分配过程

将刚创建的新对象放到伊甸园区,当垃圾回收时将幸存下来的对象放到幸存者0区,再次进行垃圾回收时,将幸存者0区和伊甸园区的对象放到幸存者1中,每次保证有一个幸存者区是空闲的.当一个对象经历15次垃圾回收(被回收对象默认次数是15,可以通过-XX:MaxTenuringThreshold=<N>设置次数)时依然存活,会被放入老年区,或者如果一个对象比较的,也可以直接存放到老年区中.在老年代,相对悠闲,当老年代内存不足时,触发 GC,进行老年代的内存清理. 若老年代执行了 GC 之后发现依然无法进行对象存储,会对整堆进行 GC, 之后依然无法进行对象存储, 就会产生 OOM 异常. Java.lang.OutOfMemoryError:Java heap space

为什么是15次?

在对象头中,它由4位数据去对GC年龄进行记录保存,最大为1111,即15

5.方法区

一个被线程共享的区域,主要存储加载的类字节码、class/method/field 等元数据、static final 常量、static 变量、即时编译器编译后的代码等数据。在物理上与堆是属于同一个空间,但在逻辑上对其进行区分,被称为元空间

方法区在 JVM 启动时被创建,并且它的实际的物理内存空间中和 Java 堆区一样都可以是不连续的.
方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展.
方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出, 虚拟机同样会抛出内存溢出的错误
关闭 JVM 就会释放这个区域的内存

6.本地方法栈

Java 虚拟机栈管理 java 方法的调用,而本地方法栈用于管理本地方法的调用.
本地方法栈也是线程私有的.
允许被实现成固定或者是可动态扩展的内存大小.内存溢出方面也是相同的. 如果线程请求分配的栈容量超过本地方法栈允许的最大容量抛出StackOverflowError.
本地方法是用 C 语言写的.
它的具体做法是在 Native Method Stack 中登记 native 方法,在 Execution Engine 执行时加载本地方法库.

四.本地方法接口

1.什么是本地方法?

简单来说,被native修饰的方法就是本地方法,该类方法底层不是由java语言编写,例如c

2.为什么使用本地方法?

与java环境外交互,与硬件设备交互,java属于应用程序语言,没有与硬件设备直接交互的权限

五.执行引擎

将字节码解释/编译为对应平台上的本地机器指令

什么是解释器和编译器?

解释器: 当 Java 虚拟机启动时会根据预定义的规范对字节码采用逐行解释的方式执行,将每条字节码文件中的内容“翻译”为对应平台的本地机器指令执行。
JIT(Just In Time Compiler)编译器: 就是虚拟机将源代码一次性直接编译成和本地机器平台相关的机器语言,但并不是马上执行。
为什么这样设计?

解释执行虽然效率低,但是在程序开始执行后可以立即投入使用,编译执行虽然将一些热点代码编译后缓存起来,执行效率高,但是需要花费一定时间,所以就采用开始时使用解释器执行,等编译器编译完成后就采用编译执行

六.垃圾回收机制

1.垃圾回收概述

1.1什么是垃圾?

垃圾是指没有被任何引用指向的对象,这个对象就是需要被回收的垃圾.

如果垃圾长时间不回收,这些垃圾对象会一直占用内存空间,导致空间无法被其他对象所使用,直到应用程序关闭,甚至导致内存溢出.

1.2垃圾回收概述

早期的 C/C++时代,垃圾回收基本上是手工进行的,开发人员可以使用 new 关键字进行内存申请,并使用 delete 关键字进行内存释放。这种方式可以灵活控制内存释放的时间,但是会给开发人员带来频繁申请和释放内存的管理负担。倘若有一处内存区间由于程序员编码的问题忘记被回收,那么 就会产生内存泄漏,垃圾对象永远无法被清除,随着系统运行时间的不断增长,垃圾对象所耗内存可能持续上升,直到出现内存溢出并造成应用程序崩溃。

现在,除了 Java 以外,C#、Python、Ruby 等语言都使用了自动垃圾回收的思想,也是未来发展趋势,可以说这种自动化的内存分配和来及回收方式已经成为了现代开发语言必备的标准。
垃圾收集器可以对年轻代,也可以对老年代,方法区的回收,其中,Java 堆是垃圾收集器的工作重点
从次数上讲:
频繁收集 Young 区
较少收集 Old 区
基本不收集元空间(方法区)

2.垃圾回收的相关算法

2.1垃圾回收标记阶段算法
标记阶段的目的: 主要是为了判断对象是否是垃圾对象
2.1.1引用计数算法
引用计数算法(Reference Counting)比较简单,对每个对象保存一个整型的引用计数器属性。用于记录对象被引用的情况。
工作原理:对于一个对象 A,只要有任何一个引用指向了对象 A,则对象 A 的引用计数器 就加 1;当引用失效时,引用计数器就减 1。只要对象 A 的引用计数器的值为 0,即表示对象 A 不可能再被使用,可进行回收
优点: 实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟性。
缺点:
1.它需要单独的字段存储计数器,这样的做法 增加了存储空间的开销
2.无法解决循环引用问题
多个对象之间相互引用,计数器不为0,但是此时这几个对象,与外界已经没有联系了,使用不到了,他们相互又有引用,垃圾收集器不能回收他们,造成内存泄漏
2.1.2可达性分析算法
可达性分析算法:也可以称为根搜索算法、追踪性垃圾收集,这里的可达性分析就是 Java、C#选择的
相对于引用计数算法而言,可达性分析算法不仅同样具备实现简单和执行高效等特点,更重要的是该算法可以有效地解决在引用计数算法中循环引用的问题 ,防止内存泄漏的发生。
工作原理:
可达性分析算法是以根(GCRoots)为起始点,按照从上至下的方式搜索被根对象所连接的目标对象是否可达。使用可达性分析算法后,内存中的存活对象都会被根直接或间接连接着,搜索所走过的路径称为引用链(Reference Chain)如果目标对象没有任何引用链相连,则是不可达的,就意味着该对象己经死亡,可以标记为垃圾对象。

哪些对象可以称为活跃对象(GCroots)?
1.虚拟机栈中引用的对象
2.方法区中类静态属性引用的对象
3.所有同步锁synchronized持有的对象
4.java虚拟机内部的引用
基本数据类型对应的class对象,一些常驻的异常对象(nullpointerexception,outofmemoryerror),系统类加载器

2.2垃圾回收阶段算法
当成功区分出内存中存活对象和死亡对象后,GC 接下来的任务就是执行垃
圾回收,释放掉无用对象所占用的内存空间,以便有足够的可用内存空间为新对
象分配内存。目前在 JVM 中比较常见的三种垃圾收集算法是:
标记-复制算法(Copying)
标记-清除算法(Mark-Sweep)
标记-压缩算法(Mark-Compact)
2.2.1  标记-复制算法(Copying)
将可用内存空间分为两块,使用是只使用一块,在垃圾回收时,会将正在使用的内存空间中的存活对象复制到未使用的内存空间中,然后将正在使用的内存空间的所有对象进行回收,交换两个空间的角色,完成垃圾回收
复制算法适合存活对象少,垃圾对象多,特别适合收新生代。
2.2.2  标记-清除算法(Mark-Sweep)
清除: 这里所谓的清除并不是真的置空,而是把需要清除的对象地址保存在空闲的地址列表里。下次有新对象需要加载时,判断垃圾的位置空间是否够,如果够,就存放(也就是覆盖原有的地址)。
2.2.3  标记-压缩算法(Mark-Compact)
将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间。
复制算法的高效性是建立在存活对象少、垃圾对象多的前提下的。这种情况在新生代经常发生,但是在老年代,更常见的情况是大部分对象都是存活对象。
如果依然使用复制算法,由于存活对象较多,复制的成本也将很高。因此,基于老年代垃圾回收的特性,需要使用其他的算法。
标记-清除算法的确可以应用在老年代中,但是在执行完内存回收后还会产生内存碎片,所以 JVM 的设计者需要在此基础之上进行改进。
标记-压缩算法的最终效果等同于标记-清除算法执行完成后,再进行一次内存碎片整理,因此,也可以把它称为标记-清除-压缩(Mark-Sweep-Compact)算法。
二者的本质差异在于标记-清除算法是一种非移动式的回收算法(空闲列表记录位置),标记-压缩是移动式的。

3.垃圾回收器

如果说垃圾收集算法是内存回收的方法论,那么收集器就是内存回收的实践者.
垃圾收集器没有在 java 虚拟机规范中进行过多的规定,可以由不同的厂商、不同版本的 JVM 来实现。
由于 JDK 的版本处于高速迭代过程中,因此 Java 发展至今已经衍生了众多的垃圾回收器。从不同角度分析垃圾收集器,可以将 GC 分为不同的类型。
3.1垃圾回收器分类
按线程数可以分为 单线程(串行) 垃圾回收器和 多线程(并行) 垃圾回收器
按照工作模式分,可以分为 独占式 并发式 垃圾回收器。
按工作的内存区间分,又可分为 年轻代垃圾回收器 老年代垃圾回收器。
3.2垃圾回收器的性能指标
吞吐量:运行用户代码的时间占总运行时间的比例 (总运行时间:程序的运行时间+ 内存回收的时间)
垃圾收集开销:垃圾收集所用时间与总运行时间的比例。
暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间。
内存占用: Java 堆区所占的内存大小。
3.3CMS回收器
CMS(Concurrent Mark Sweep,并发标记清除)收集器是以获取最短回收停顿时间为目标的收集器( 追求低停顿 ),它在垃圾收集时使得用户线程和 GC 线程并发执行,因此在垃圾收集过程中用户也不会感到明显的卡顿。
垃圾回收过程
初始标记:Stop The World,仅使用一条初始标记线程对所有与 GC Roots 直接关联的对象进行标记。
并发标记:垃圾回收线程,与用户线程并发执行。此过程进行可达性分析,标记出所有废弃对象。
重新标记:Stop The World,使用多条标记线程并发执行,将刚才并发标记过程中新出现的废弃对象标记出来。
并发清除:只使用一条 GC 线程,与用户线程并发执行,清除刚才标记的对象。这个过程非常耗时。
并发标记与并发清除过程耗时最长,且可以与用户线程一起工作,因此,总体上说,CMS 收集器的内存回收过程是与用户线程一起并发执行的。
3.4G1回收器
G1(Garbage-First)垃圾回收器是在 Java7 update 4 之后引入的一个新的垃圾回收器,是当今收集器技术发展的最前沿成果之一.是一款面向服务端应用的垃圾收集器。
G1 是一个并行回收器,它把堆内存分割为很多不相关的区域(Region)(物理上不连续的逻辑上连续的)。使用不同的 Region 来表示 Eden、幸存者0 区,幸存者 1 区,老年代等。
G1 GC 有计划地避免在整个 Java 堆中进行全区域的垃圾收集。G1 跟踪各个 Region 里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region.
由于这种方式的侧重点在于回收垃圾最大量的区间(Region),所以我们给 G1 一个名字:垃圾优先(Garbage First)。
① 初始标记:标记出 GC Roots 直接关联的对象,这个阶段速度较快,需要停止用户线程,单线程执行。
② 并发标记:从 GC Root 开始对堆中的对象进行可达新分析,找出存活对象,这个阶段耗时较长,但可以和用户线程并发执行。
③ 最终标记:修正在并发标记阶段引用户程序执行而产生变动的标记记录。

④ 筛选回收:筛选回收阶段会对各个 Region 的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来指定回收计划(用最少的时间来回收包含垃圾最多的区域.这就是 Garbage First 的由来——第一时间清理垃圾最多的区块),这里为了提高回收效率,并没有采用和用户线程并发执行的方式,而是停顿用户线程。
适用场景:要求尽可能可控 GC 停顿时间;内存占用较大的应用。

 

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

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

相关文章

LeetCode LCR157 套餐内商品的排列顺序

生成字符串的全部排列&#xff08;去重&#xff09;&#xff1a;从问题到解决方案的完整解析 问题背景 在编程和算法设计中&#xff0c;生成字符串的所有排列是一个经典问题。它不仅出现在算法竞赛中&#xff0c;也在实际开发中有着广泛的应用&#xff0c;比如生成所有可能的…

pgsql:关联查询union(并集)、except(差集)、intersect(交集)

pgsql:关联查询union(并集)、except(差集)、intersect(交集)_pgsql except-CSDN博客

微信小程序中使用ECharts 并且动态设置数据

项目下载地址 GitHub 地址 https://github.com/ecomfe/echarts-for-weixin 将当前文件夹里的内容拷贝到项目中 目录&#xff1a; json: {"usingComponents": {"ec-canvas": "../components/ec-canvas/ec-canvas"} }wxml&#xff1a; <ec…

RV1126 人脸识别门禁系统解决方案

1. 方案简介 本方案为类人脸门禁机的产品级解决方案,已为用户构建一个带调度框架的UI应用工程;准备好我司的easyeai-api链接调用;准备好UI的开发环境。具备低模块耦合度的特点。其目的在于方便用户快速拓展自定义的业务功能模块,以及快速更换UI皮肤。 2. 快速上手 2.1 开…

深度学习ResNet模型提取影响特征

大家好&#xff0c;我是带我去滑雪&#xff01; 影像组学作为近年来医学影像分析领域的重要研究方向&#xff0c;致力于通过从医学图像中高通量提取大量定量特征&#xff0c;以辅助疾病诊断、分型、预后评估及治疗反应预测。这些影像特征涵盖了形状、纹理、灰度统计及波形变换等…

DeepSeek 接入 Word 完整教程

一、前期准备 1.1 注册并获取 API 密钥 访问 DeepSeek 平台&#xff1a; 打开浏览器&#xff0c;访问 DeepSeek 官方网站&#xff08;或您使用的相应平台&#xff09;。注册并登录您的账户。 创建 API 密钥&#xff1a; 在用户控制面板中&#xff0c;找到“API Keys”或“API…

驱动开发硬核特训 · Day 7:深入掌握 Linux 驱动资源管理机制(Resource Management)

&#x1f50d; B站相应的视屏教程&#xff1a; &#x1f4cc; 内核&#xff1a;博文视频 - 总线驱动模型实战全解析 —— 以 PCA9450 PMIC 为例 敬请关注&#xff0c;记得标为原始粉丝。 &#x1f6a9; 在 Linux 驱动开发中&#xff0c;资源管理机制决定了驱动的稳定性与可靠性…

什么是TensorFlow?

TensorFlow 是由 Google Brain 团队开发的开源机器学习框架&#xff0c;被广泛应用于深度学习和人工智能领域。它的基本概念包括&#xff1a; 1. 张量&#xff08;Tensor&#xff09;&#xff1a;在 TensorFlow 中&#xff0c;数据以张量的形式进行处理。张量是多维数组的泛化…

【ChCore Lab 01】Bomb Lab 拆炸弹实验(ARM汇编逆向工程)

文章目录 1. 前言2. 实验代码版本问题3. 关于使用问题4. 宏观分析5. read_line 函数介绍6. phase_0 函数6.1. read_int 函数6.2. 回到 phase_0 函数继续分析6.3. 验证结果 7. phase_1 函数7.2. 验证结果 8. phase_2 函数8.1. read_8_numbers 函数8.2. 回到 phase_2 函数继续分析…

《Vue Router实战教程》20.路由懒加载

欢迎观看《Vue Router 实战&#xff08;第4版&#xff09;》视频课程 路由懒加载 当打包构建应用时&#xff0c;JavaScript 包会变得非常大&#xff0c;影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块&#xff0c;然后当路由被访问的时候才加载对应组件&am…

docker 多主机容器组网

一、服务器A 1、初始化Swarm集群&#xff08;管理节点&#xff09; docker swarm init --advertise-addr 主节点ip 2、获取工作节点​​加入Swarm集群所需的Token 和完整命令 docker swarm join-token worker 3、创建Overlay网络 docker network create -d overlay --subnet…

rancher 解决拉取dashboard-shell镜像失败的问题

问题背景 在 Kubernetes 集群中部署 Rancher 后&#xff0c;点击右上角的 "Shell" 按钮时&#xff0c;Rancher 会动态创建一个 dashboard-shell-xxxxx Pod&#xff0c;用于提供 Web 终端功能。然而&#xff0c;由于默认镜像 rancher/shell:v0.1.21 托管在 Docker Hu…

OpenCV day2

Matplotlib相关知识 Matplotlib相关操作&#xff1a; import numpy as np from matplotlib import pyplot as pltx np.linspace(0, 2 * np.pi, 100) y1 np.sin(x) y2 np.cos(x)# 使用红色虚线&#xff0c;圆点标记&#xff0c;线宽1.5&#xff0c;标记大小为6绘制sin plt.p…

【网络安全】通过 JS 寻找接口实现权限突破

未经许可,不得转载。 本文所述所有风险点均已修复。 文章目录 引言正文引言 以下些漏洞已被起亚方面修复;起亚方面确认,这些漏洞从未被恶意利用过。 2024年6月11日,我们发现起亚汽车存在一系列严重安全漏洞,攻击者仅凭车牌号即可远程控制车辆的核心功能。该攻击不需要接触…

LabVIEW 发电机励磁系统监测与诊断

在现代工业体系中&#xff0c;发电机作为关键的电能转换设备&#xff0c;其稳定运行对于电力供应的可靠性起着决定性作用。而励磁系统作为发电机的核心控制部分&#xff0c;直接影响着发电机的性能和电力系统的稳定性。一旦励磁系统出现故障&#xff0c;可能引发发电机电压波动…

MacOS红队常用攻击命令

MacOS红队常用攻击命令 1.自动化武器2.系统信息3.服务 & 内核信息4.快捷命令5.网络相关6.brew相关 / 软件包相关7.高权限命令8.创建一个管理员权限的后门用户 1.自动化武器 1、linPEAS LinPEAS 是一个脚本&#xff0c;用于在 Linux/Unix/MacOS 主机上搜索提权路径 2、me…

【数据结构_8】栈和队列

一、反向输出链表元素 Ⅰ使用递归进行反向输出 package stack; public class Test2 {static class Node{public String val;public Node next;//构造方法public Node(String val) {this.val val;this.next null;}}//利用递归来反向输出链表public static void reverse(Nod…

Java 正则表达式综合实战:URL 匹配与源码解析

在 Web 应用开发中&#xff0c;我们经常需要对 URL 进行格式验证。今天我们结合 Java 的 Pattern 和 Matcher 类&#xff0c;深入理解正则表达式在实际应用中的强大功能&#xff0c;并剖析一段实际的 Java 示例源码。 package com.RegExpInfo;import java.util.regex.Matcher; …

虾分发平台平台优势

平台优势 高效与成本优化 一键分发与自动化工具减少人工操作&#xff0c;加速测试周期&#xff1b;免费分发流量和透明价格套餐降低中小团队开支。 安全与合规 自研CDN与封装技术平衡性能与安全性&#xff0c;适配复杂分发场景&#xff1b;全球CDN网络加速保障极速下载。 服务…

c语言学习16——内存函数

内存函数 一、memcpy使用和模拟实现1.1参数1.2 使用1.3 模拟实现 二、memmove使用和模拟实现2.1 参数2.2 使用2.3 模拟实现 三、memset使用3.1 参数3.2 使用 四、memcmp使用4.1 参数4.2 使用 一、memcpy使用和模拟实现 1.1参数 因为内存中不知道存的是什么类型的地址&#xff…