当前位置: 首页 > news >正文

JVM执行引擎JIT深度剖析

前端编译与后端编译

Java 程序的编译过程是分两个部分的。一个部分是从java文件编译成为class文件,这一部分也称为前端编译。另一个部分则是这些class文件,需要进入到 JVM 虚拟机,将这些字节码指令编译成操作系统识别的具体机器指令。这一部分也称为后端编译。

其中前端编译是在 JVM 虚拟机之外执行,所以与 JVM 虚拟机没有太大的关系。任何编程语言,只要能够编译出满足 JVM 规范的 Class 文件,就可以提交到 JVM 虚拟机执行。至于编译的过程,如果你不是想要专门去研究语言,那么就没有必要太过深入的去了解了。这里就暂时略过。我们更关注JVM 在后端编译过程中如何提升执行的效率。

字节码指令是如何执行的

解释执行与编译执行

Class 文件当中就已经保留了每一行 Java 代码对应的字节码指令,也就是说,执行引擎要如何执行一段 Java 代码,其实早在 Class 文件当中就已经确定了。执行引擎要做的事情,其实就是将这些Class文件中的字节码指令翻译成对应操作系统的机器码,然后扔给服务器执行就行了。 本质上,就相当于是一个翻译。

那么怎么做这个翻译工作呢?最简单的方式,当然就是来一个指令就翻译一次。就像是一个无脑的翻译机器,不用管合不合理,按字翻译就是了。没错,早期的JVM执行引擎其实就是这么做的,这种执行方式,就称为解释执行

但是这种方式需要在上层语言和机器码之间经过中间一层JVM字节码的转换,显然执行效率是比不上 C 和 C那些直接面向本地机器指令编程的语言的,这也是长久以前,Java 被 C 和 C开发者吐槽执行速度慢的根源。

那么要怎么提升JAVA的执行效率呢?

JAVA的基本思想就是维护一个缓存,CodeCache,将那些字节码指令,提前编译出来,放到缓存里。到执行的时候,直接从缓存中查出来就好了。这种先编译,后执行的方式,就称为编译执行

​ 但是JAVA官方也不知道程序员会写出什么样稀奇古怪的代码,所以,自然没办法提前维护出一个完整的字节码缓存。那么就只能退而求其次,将那些运行频率最高的热点代码提前编译出来,放到缓存里。这样,至少最常用的那些方法的调用效率能够提高。完成这个任务的编译器,称为即时编译器 JIT(Just In Time Compiler)。

​ 使用java -version就可以看到当前使用的是哪种执行模式。

 从这里可以看到,HotSpot虚拟机并没有直接选择执行效率更快的编译执行,而是默认采用的一种混合执行的方式。

为什么JVM不直接采用性能明显更高的编译执行模式呢?这是因为虽然编译执行可以将越来越多的代码编译成本地代码,这样可以减少解释器的中间损耗,获得更高的执行效率。但是,这也意味着对内存有更多的资源限制,在很多资源比较紧张的场景,比如客户端应用,嵌入式系统等,使用解释执行就能更节约内存。

另外,编译执行需要较长的预热过程。在 CodeCache 中的代码缓存维护好之前,编译执行相比解释执行需要额外的性能消耗,用来识别热点代码,维护 CodeCache 。同时,编译执行在识别热点代码的过程中,还需要解释执行来帮助提供一些信息支持。在 HotSpot 中,会默认使用混合执行模式,而不是单纯的使用其中一种模式。

热点代码识别

 使用 JIT 实时编译的前提就是需要识别出热点代码。要知道某段代码是不是热点代码,是不是需要触发即时编译,这个行为称为“热点探测”(Hot Spot Code Detection)。热点探测有很多种实现思路,而在 HotSpot 虚拟机中采用的是一种基于计数器的热点探测方法。HotSpot 为每个方法准备了两类计数器: 方法调用计数器(Invocation Counter)和回边计数器(Back Edge Counter)。当虚拟机运行参数确定的前提下,这两个计数器都有一个明确的阈值,计数器阈值一旦溢出,就会触发即时编译。

首先来看看方法调用计数器。顾名思义,这个计数器就是用于统计方法被调用的次数。每次调用一个方法时,就记录一次这个方法的执行次数。当他的执行次数非常多,超过了某一个阈值,那么这个方法就可以认为是热点方法。这个方法对应的代码,自然也就是热点代码了。这时就可以向JIT提交一个针对该方法的代码编译请求了。

方法调用技术器的默认阈值是10000次,这个阈值可以通过虚拟机参数-XX:CompileThreshold来设定。当一个方法被调用时,虚拟机会先检查该方法是否存在被即时编译过的版本,如果存在,则优先使用编译后的本地代码来执行。如果不存在已被编译过的版本,则将该方法的调用计数器值加一,然后判断方法调用计数器与回边计数器值之和是否超过方法调用计数器的阈值。一旦已超过阈值的话,将会向即时编译器提交一个该方法的代码编译请求。整体流程如下图:

比如这个方法计数器的默认阈值,就可以使用 java -XX:+PrintFlagsInitial -version 指令查询。

方法计数器以方法为维度,自然是不够精细的。所以,要更精细的识别热点代码,还需要配合接下来的回边计数器

回边计数器,它的作用是统计一个方法中循环体代码执行的次数。在字节码中遇到控制流向后跳转的指令就称为“回边(Back Edge)”,很显然建立回边计数器统计的目的是为了发现一个方法内部频繁的循环调用。回边计数器在服务端模式下默认的阈值是 10700

当解释器遇到一条回边指令时,会先查找将要执行的代码片段是否有已经编译好的版本,如果有的话,它将会优先执行已编译的代码,否则就把回边计数器的值加一,然后判断方法调用计数器与回边计数器值之和是否超过回边计数器的阈值。当超过阈值的时候,将会提交一个编译请求,并且把回边计数器的值稍微降低一些,以便继续在解释器中执行循环,等待编译器输出编译结果,整个执行过程如下图。

C1、C2与Graal编译器

 在JDK1.8中 HotSpot 虚拟机中,内置了两个 JIT,分别为 C1 编译器和 C2 编译器。

 C1编译器

C1 编译器是一个简单快速的编译器,主要的关注点在于局部性的优化,适用于执行时间较短或对启动性能有要求的程序,例如,GUI 应用对界面启动速度就有一定要求,C1也被称为 Client Compiler。

C1编译器几乎不会对代码进行优化

C2编译器

C2 编译器是为长期运行的服务器端应用程序做性能调优的编译器,适用于执行时间较长或对峰值性能有要求的程序。根据各自的适配性,这种即时编译也被称为Server Compiler。

但是C2代码已超级复杂,无人能维护!所以才会开发Java编写的Graal编译器取代C2(JDK10开始)

分层编译

分层编译根据编译器编译、优化的规模与耗时,划分出不同的编译层次

等级描述性能
0程序纯解释执行,并且解释器不开启性能监控功能(Profiling)1
1使用C1编译器将字节码编译为本地代码来运行,进行简单可靠的稳定优化。不开启性能监控功能。4
2仍然使用C1编译器执行,仅开启方法及回边次数统计等有限的性能监控功能。3
3仍然使用C1编译器执行,开启全部性能监控,除了第2层的统计信息外,还会收集如分支跳转、虚方法调用版本等全部的统计信息。2
4使用C2编译器将字节码编译为本地代码,相比起C1编译器,C2编译器会启用更多编译耗时更长的优化,还会根据性能监控信息进行一些不可靠的激进优化。5

后端编译优化技术

方法内联 Inline

方法内联的优化行为就是把目标方法的代码复制到发起调用的方法之中,避免发生真实的方法调用。这样就可以减少频繁创建栈帧的性能开销。

例如以下方法:

最终会被优化为:

JVM 会自动识别热点方法,并对它们使用方法内联进行优化。

我们可以通过 -XX:CompileThreshold 来设置热点方法的阈值。

但要强调一点,热点方法不一定会被 JVM 做内联优化,如果这个方法体太大了,JVM 将不执行内联操作。

而方法体的大小阈值,我们也可以通过参数设置来优化:

经常执行的方法,默认情况下,方法体大小小于 325 字节的都会进行内联,我们可以通过 -XX:FreqInlineSize=N 来设置大小值;

 

不是经常执行的方法,默认情况下,方法大小小于 35 字节才会进行内联,我们也可以通过 -XX:MaxInlineSize=N 来重置大小值。

 

逃逸分析 Escape Analysis

当一个对象在方法里面被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,这种称为方法逃逸;甚至还有可能被外部线程访问到,譬如赋值给可以在其他线程中访问的实例变量,这种称为线程逃逸;从不逃逸、方法逃逸到线程逃逸,称为对象由低到高的不同逃逸程度。

左侧的代码中,t对象,不会被外部引用,只会在方法中使用,所以不会发生逃逸。而右侧的代码中,t对象就很明显被其他方法使用了,这就会产生逃逸。JDK8 中默认开启了逃逸分析,可以添加参数 -XX:-DoEscapeAnalysis 主动关闭逃逸分析。

如果能证明一个对象不会逃逸到方法或线程之外,那么 JIT 就可以为这个对象实例采取后续一系列的优化措施。 

第一个是标量替换(Scalar Replacement)。若一个数据已经无法再分解成更小的数据来表示了,Java虚拟机中的原始数据类型(int、long等数值类型及reference类型等)都不能再进一步分解了,那么这些数据就可以被称为标量。如果把一个Java对象拆散,根据程序访问的情况,将其用到的成员变量恢复为原始类型来访问,这个过程就称为标量替换。假如逃逸分析能够证明一个对象不会被方法外部访问,并且这个对象可以被拆散,那么程序真正执行的时候将可能不去创建这个对象,而改为直接创建它的若干个被这个方法使用的成员变量来代替。将对象拆分后,除了可以让对象的成员变量在栈上分配和读写之外,还可以为后续进一步的优化手段创建条件。标量替换对逃逸程度的要求更高,它不允许对象逃逸出方法范围内。JDK8 中默认开启了标量替换,可以通过添加参数 -XX:-EliminateAllocations 主动关闭标量替换。

第二个是栈上分配( Stack Allocations)。正常情况下,JVM 中所有对象都应该创建在堆上,并由 GC 线程进行回收。如果确定一个对象不会逃逸出线程之外,那让这个对象在栈上分配内存将会是一个很不错的主意,对象所占用的内存空间就可以随栈帧出栈而销毁。在一般应用中,完全不会逃逸的局部对象和不会逃逸出线程的对象所占的比例是很大的,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了,垃圾收集子系统的压力将会下降很多。栈上分配可以支持方法逃逸,但不能支持线程逃逸。

这三种优化措施中,逃逸分析是基础。因为虚拟机栈是对应一个线程的,而堆内存是对应整个Java进程的。如果发生了线程逃逸,那么堆中的同一个对象,可能隶属于多个线程,这时要将堆中的对象挪到虚拟机栈中,那就必须扫描所有的虚拟机栈,看看在这个虚拟机栈对应的线程中是否引用了这个对象。这个性能开销是难以接受的。

​ 而栈是一个非常小的内存结构,他也不可能像堆中那么豪横的使用内存空间,所以,也必须要对对象进行最大程度的瘦身,才能放到栈中。而瘦身的方式,就是去掉对象的mark标志位中的补充信息,拆分成最精简的标量。所以,要开启栈上分配,标量替换也是不可或缺的。

可以用下面示例方法进行一下验证:

public class EscapeAnalysisTest {public static void main(String[] args) throws InterruptedException {long start = System.currentTimeMillis();for (int i = 0; i < 10000000; i++) {allocate();}System.out.println("运行耗时:"+(System.currentTimeMillis()-start));Thread.sleep(6000000);}static void allocate(){MyObject myObject = new MyObject(2024,2024.6);}static class MyObject {int a;double b;MyObject(int a,double b){this.a = a;this.b = b;}}
}

以我的测试环境来看,默认情况下, 运行时间大概 2 毫秒,而关闭逃逸分析或者关闭标量替换后,运行时间就扩大到了 44毫秒左右。

锁消除 lock elision

这也是经过逃逸分析后可以直接进行的优化措施。

​ 这个优化措施主要是针对 synchronized 关键字。当 JVM 检测到一个锁的代码不存在多线程竞争时,会对这个对象的锁进行锁消除。

 比如下面的示例代码:

public class LockElisionDemo {public static String BufferString(String s1,String s2){StringBuffer sb = new StringBuffer();sb.append(s1);sb.append(s2);return sb.toString();}public static String BuilderString(String s1, String s2){StringBuilder sb = new StringBuilder();sb.append(s1);sb.append(s2);return sb.toString();}public static void main(String[] args) {long startTime = System.currentTimeMillis();for (int i = 0; i < 100000000; i++) {BufferString("aaaaa","bbbbbb");}System.out.println("StringBuffer耗时:"+(System.currentTimeMillis()-startTime));long startTime2 = System.currentTimeMillis();for (int i = 0; i < 100000000; i++) {BuilderString("aaaaa","bbbbbb");}System.out.println("StringBuilder耗时:"+(System.currentTimeMillis()-startTime2));}
}

 其中分别测试了 StringBuffer 和 StringBuilder 的字符串构建方法。这两个方法功能上没有什么区别,最大的区别在于,StringBuffer 是线程安全的,他的append和toString都是加了 synchronized 同步锁的,而 StringBuilder 则没有加。之前介绍过,synchronized 关键字其实是在Class文件中添加了monitorenter和monitorexit两个字节码指令的,所以,StringBuffer显然要比 StringBuilder 更慢。

在当前代码中,BufferString 方法只是在main这一个线程里调用,不存在线程竞争,所有这个synchronized 同步锁是没有作用的,因此,在触发了 JIT 后,JVM 会在编译时就会将这个无用的锁消除掉。这样,两个方法的耗时是差不多的。

StringBuffer耗时:1521
StringBuilder耗时:1039

与之形成对比,如果给这个示例代码添加一个JVM 参数: -XX:-EliminateLocks 主动关闭锁清除后,再执行这个案例,两个方法的耗时差距就明显更大了。

StringBuffer耗时:2461
StringBuilder耗时:1049

 

相关文章:

JVM执行引擎JIT深度剖析

前端编译与后端编译 Java 程序的编译过程是分两个部分的。一个部分是从java文件编译成为class文件&#xff0c;这一部分也称为前端编译。另一个部分则是这些class文件&#xff0c;需要进入到 JVM 虚拟机&#xff0c;将这些字节码指令编译成操作系统识别的具体机器指令。这一部…...

【DOCKER】基于DOCKER的服务之DUFS

文件上传下载服务器&#xff1a;https://github.com/sigoden/dufs # 拉取镜像 docker pull sigoden/dufs# 创建数据卷文件夹 mkdir -p /data/.docker/volumes/dufs# 创建容器 docker run -id --restartalways --name dufs \-p 51080:5000 \-v /data/.docker/volumes/dufs:/dat…...

加密货币地址的基本概念

什么是地址&#xff1f; 在日常生活中&#xff0c;地址可能指房屋、电子邮件或官网的位置&#xff0c;用来精确定位在系统中的特定位置或端点。在加密货币领域&#xff0c;地址也起着类似的基础作用&#xff0c;只不过是在数字环境中。 加密货币地址是区块链网络中使用的唯一…...

如何在 Linux 服务器上部署 Pydio Cells 教程

简介 Pydio Cells 是一个开源的文档共享和协作平台&#xff0c;专为你的组织设计。它允许你在组织内部分享文档和文件&#xff0c;并让你完全掌控文档共享环境。 在本教程中&#xff0c;我们将向你展示如何在 Alma Linux 9 服务器上安装 Pydio Cells。你将使用 MariaDB 数据库…...

Halcon例程代码解读:安全环检测(附源码|图像下载链接)

安全环检测核心思路与代码详解 项目目标 本项目的目标是检测图像中的安全环位置和方向。通过形状匹配技术&#xff0c;从一张模型图像中提取安全环的特征&#xff0c;并在后续图像中识别多个实例&#xff0c;完成检测和方向标定。 实现思路 安全环检测分为以下核心步骤&…...

Selenium 全面指南

Selenium 是一个强大的 Web 自动化工具&#xff0c;支持多种浏览器和语言绑定。 1. Selenium 的基本概念 WebDriver&#xff1a;Selenium 提供的核心接口&#xff0c;用于控制浏览器操作。显式等待&#xff1a;等待特定条件满足后再执行操作。隐式等待&#xff1a;全局设置一个…...

#error: WinSock.h has already been included解决方案

原因&#xff1a; 在工程中使用了 Boot 库之后&#xff0c;使用了socket、tcp 相关的头文件&#xff0c;在其他地方还是包括了头文件<windows.h>&#xff0c;该头文件内包含了<winsock.h>。导致遇到报错问题&#xff1a;WinSock.h has already been included 解决…...

2.Couchbase 的增量查询优化

在 Couchbase 中实现增量查询的优化是关键&#xff0c;尤其当数据量庞大时。通过合适的策略&#xff0c;可以显著提高增量查询的效率&#xff0c;确保系统在处理实时数据时的响应速度和性能。下面是一些针对 Couchbase 增量查询的优化策略。 1. 使用索引优化查询 为了提升增量…...

汽车IVI中控开发入门及进阶(46):FFmpeg

概述: FFmpeg 是领先的多媒体框架,能够解码、编码、 转码、复用、解复用、流、过滤和播放 几乎所有人类和机器创建的东西。它支持最模糊的古老格式,直到最前沿。无论它们是由某个标准委员会、社区还是公司设计的。它还具有高度的可移植性:FFmpeg 在各种构建环境、机器架构…...

Spring Boot 中的 @Scheduled 定时任务以及开关控制

Scheduled注解是Spring框架&#xff08;包括Spring Boot&#xff09;中用于实现定时任务的一种方式。以下是对Scheduled注解的详细解析&#xff1a; 一、基本概念 Scheduled注解允许开发者在Spring容器中定义定时任务。通过简单地在一个方法上添加Scheduled注解&#xff0c;S…...

服务器证书原理

CA&#xff08;Certificate Authority&#xff09;证书是由 证书颁发机构&#xff08;CA&#xff09;本身签名的。具体来说&#xff0c;这取决于 CA 的类型和其在信任链中的位置&#xff1a; 1. 自签名证书 根 CA 证书 是信任链的起点&#xff0c;由 CA 自己签名。它们是信任链…...

重温设计模式--代理、中介者、适配器模式的异同

文章目录 1、相同点2、不同点 1、相同点 目的都是为了更好地处理对象之间的关系&#xff1a;这三种模式都是在软件设计中用于处理对象之间的关联和交互&#xff0c;以达到优化系统结构、增强可维护性等目的。它们都在一定程度上隐藏了对象之间的某些细节或者复杂性&#xff0c…...

2024第十六届蓝桥杯模拟赛(第二期)-Python

# 2024第十六届蓝桥杯模拟赛&#xff08;第二期&#xff09;-Python题解 # 自己改注释# -----------------------1------------------------ # def prime(x): # if x < 2: # return 0 # for i in range(2, int(x ** 0.5) 1): # if x % i 0: # …...

分布式系统中的防抖策略一致性与性能优化

目录 引言分布式系统的挑战防抖策略简介确保多实例间一致性的方法 幂等操作TTL缓存 分布式一致性事件总线或消息队列异步任务调度器客户端或API网关层面的防抖一致性哈希与分区限流和熔断机制 避免锁竞争导致的性能瓶颈Java示例代码结论 引言 在现代软件架构中&#xff0c;…...

项目代码第6讲:UpdownController.cs;理解 工艺/工序 流程、机台信息;前端的“历史 警报/工艺 记录”

一、UpdownController.cs 1、前端传入 当用户在下图的“记录查询”中的 两个界面选项 中,点击“导出”功能时,向后端发起请求,请求服务器下载文件的权限 【权限是在Program.cs中检测的,这个控制器里只需要进行“谁在哪个接口下载了文件”的日志记录】 【导出:是用户把…...

【计算机视觉基础CV-图像分类】03-深度学习图像分类实战:鲜花数据集加载与预处理详解

本文将深入介绍鲜花分类数据集的加载与处理方式&#xff0c;同时详细解释代码的每一步骤并给出更丰富的实践建议和拓展思路。以实用为导向&#xff0c;为读者提供从数据组织、预处理、加载到可视化展示的完整过程&#xff0c;并为后续模型训练打下基础。 前言 在计算机视觉的深…...

大模型应用技术系列(一):大模型应用整体技术栈浅析

RAG相关的技术学习暂时告一段落了,接下来尝试探索新的学习方向。这就引入一个问题:接下来该做什么?为了能进一步推进,我需要有一个整体的视角,从更上层来看整个技术栈,从而确定接下来感兴趣的方向。本文主要探索从更上层的视角来看构建大模型的技术栈,从而进一步确定研究…...

绿色环保木塑复合材料自动化生产线设计书

《绿色环保木塑复合材料自动化生产线设计书》 一、项目概述 随着全球对环境保护和可持续发展的日益重视,绿色环保材料的研发与生产成为了热门领域。木塑复合材料作为一种新型的绿色环保材料,它将木材纤维与塑料通过特定工艺复合而成,兼具木材与塑料的双重特性,具有防水、…...

Sourcegraph 概述

Sourcegraph 报告 Sourcegraph 是一款强大的代码搜索和智能导航工具&#xff0c;专为大型代码库、分布式系统和跨多个仓库的开发环境设计。它能显著提高开发者对复杂系统的理解和维护效率&#xff0c;帮助团队在庞大的代码库中快速找到关键信息。本文将详细讲解 Sourcegraph 的…...

c 保存 csv格式的文件

在C语言中保存数据为CSV&#xff08;逗号分隔值&#xff09;格式的文件&#xff0c;你可以使用标准I/O库函数&#xff0c;如fprintf&#xff0c;来将数据写入文件&#xff0c;并确保每个字段之间用逗号分隔。以下是一个简单的示例&#xff0c;说明如何在C语言中创建一个CSV文件…...

C语言扫雷游戏教学(有图形界面)(提供源码+实验报告)(计时+排行榜+难度选择+登录注册+背景音乐)(涉及easyX库)

前言&#xff1a; 本篇文章篇幅较长&#xff0c;请根据自己的需求在目录上跳转对应内容哦&#xff01;源码及实验报告的获取在文章的后面哦&#xff01;本人代码水平不佳&#xff0c;希望本文章和项目能带给大家帮助&#xff01; 目录 前言&#xff1a; 一.成果预览&#x…...

第五节:GLM-4v-9b模型model加载源码解读(模型相关参数方法解读)

文章目录 前言一、GLM-4v-9b模型model加载源码解读1、GLM-4v-9b模型model加载主函数源码2、GLM-4v-9b模型model加载源码源码解读3、GLM-4v-9b自定义模型类源码解读 二、基于GLM-4v-9b模型获取模型输入参数等内容源码解读(from_pretrained-->huggingface)1、from_pretrained函…...

面试经验分享 | 北京渗透测试岗位

更多大厂面试经验的视频经验分享看主页 目录&#xff1a; 所面试的公司&#xff1a;安全大厂 所在城市&#xff1a;北京 面试职位&#xff1a;渗透测试工程师 面试方式&#xff1a;腾讯会议线上面试线下面试 面试过程&#xff1a; 面试官的问题&#xff1a; 1、说一下XSS有哪…...

unity Toggle制作滑动开关

先上效果图 重点是这个Graphic要清空,不然显示不能直接切换,会消失 using DG.Tweening; using UnityEngine; using UnityEngine.UI;public class SwitchToggle : MonoBehaviour {public RectTransform handleRect;public float duration 0.5f;private Vector2 handlePos;To…...

全面解析 Kubernetes 流量负载均衡:iptables 与 IPVS 模式

目录 Kubernetes 中 Service 的流量负载均衡模式 1. iptables 模式 工作原理 数据路径 优点 缺点 适用场景 2. IPVS 模式 工作原理 数据路径 优点 缺点 适用场景 两种模式的对比 如何切换模式 启用 IPVS 模式 验证模式 总结 Kubernetes 中 Service 的流量负载…...

【unity】【游戏开发】Unity项目一运行就蓝屏报Watch Dog Timeout

【背景】 由于是蓝屏所以没法截屏&#xff0c;总之今天遇到了一开Unity&#xff0c;过一阵就蓝屏的情况&#xff0c;报Watch Dog Timeout。 【分析】 通过任务管理器查看&#xff0c;发现Unity占用率100%&#xff0c;再观察Unity内部&#xff0c;每次右下角出现一个Global I…...

【macos java反编译工具Java Decompiler】

mac上能用的反编译工具 https://java-decompiler.github.io/...

宠物用品电子商务系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库可…...

脑肿瘤检测数据集,对9900张原始图片进行YOLO,COCO,VOC格式的标注

脑肿瘤检测数据集&#xff0c;对9900张原始图片进行YOLO&#xff0c;COCO&#xff0c;VOC格式的标注 数据集分割 训练组 70&#xff05; 6930图片 有效集 20&#xff05; 1980图片 测试集 10&#xff05; 990图片 预处理 静态裁剪&#xff1a; 24-82&…...

Adversarial Machine Learning(对抗机器学习)

之前把机器学习&#xff08;Machine Learning&#xff09;的安全问题简单记录了一下&#xff0c;这里有深入研究了一些具体的概念&#xff0c;这里记录一下方便以后查阅。 Adversarial Machine Learning&#xff08;对抗机器学习&#xff09; Adversarial Examples 相关内容Eva…...