【Linux】缓冲区/磁盘inode/动静态库

目录

一、缓冲区

(一)概念

(二)刷新策略

(三)仿写FILE

(四)内核缓冲区

二、磁盘

(一)磁盘的存储

(二)磁盘的抽象存储结构

(三)分页思想

(四)磁盘的文件系统

1、概念

2、目录结构

3、新建、查找与删除文件

三、软硬连接

(一)软链接

        1、概念

        2、软链接的建立删除

(二)硬链接

        1、概念

        2、硬链接的建立删除

        3、普通文件和目录文件的硬链接数

四、动静态库

(一)概念       

(二)动静态库的建立使用

1、静态库

2、动态库


一、缓冲区

(一)概念

        缓冲区的本质就是一段用作缓存的内存,可以节省进行数据IO的时间。

(二)刷新策略

1、立即刷新

        实际情况比较少,我们可以手动调用 fflush() 函数进行刷新。

2、行缓冲

        一般在显示屏上的输出采用行缓冲。相对于全缓冲,虽然提供了IO次数,但按行缓冲刷新对人的阅读更加友好。所以显示器采用行刷新的策略,既保证了人的阅读习惯,又使得数据IO效率不至于太低。

3、全缓冲

        当缓冲区满了以后才会刷新缓冲区。大大减少了IO次数。

4、特殊情况

        进程退出或者用户强制刷新。

5、案例

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
int main()
{printf("Hello printf\n");fprintf(stdout,"Hello fprintf\n");fputs("Hello fputs\n", stdout);const char* str = "Hello write\n";write(1, str, strlen(str));fork();return 0;
}

        当我们分别将可执行文件输出至显示屏和文件中得到的结果并不相同。

        这里我们看到,凡是调用C语言接口的输出至文件时都输出了两遍,而系统调用 write() 只输出了一遍。为什么会出现这种情况呢?

        文件操作见:【Linux】基础IO-CSDN博客

        当我们输出至显示器时,缓冲区刷新策略为行缓冲,每个语句的打印都含有 \n ,因此在 fork() 之前,缓冲区内不含有任何数据,创建的子进程的缓冲区也不含有任何数据;

        当我们将输出内容重定向输出至文件中(磁盘),缓冲区刷新策略为全缓冲,只有缓冲区满了以后才会刷新,因此在fork之前,缓冲区内含有调用C语言函数打印的内容,创建子进程之后,子进程的缓冲区也含有这些内容,最终父子进程退出后,其缓冲区内容刷新输出至文件。

        调用系统调用 write() 接口,无论刷新策略如何,该内容都只被输出了一次,因为可以得出上述的缓冲区为语言级别的缓冲区,与操作系统内核无关。

(三)仿写FILE

1、myfile.h

#pragma once
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
#define SIZE 1024
// 1,2,4二进制1的位置不一样
#define SYNC_NOW 1  // 立即刷新
#define SYNC_LINE 2 // 行刷新
#define SYNC_FULL 4 // 全刷新
typedef struct _FILE
{int flags;     // 刷新方式int fileno;    // 文件描述符int cap;       // buffer总容量int size;      // buffer当前使用量char buffer[]; // 缓冲区
} FILE_;
FILE_ *fopen_(const char *path_name, const char *mode);
void fwrite_(const void *ptr, int num, FILE_ *fp);
void fclose_(FILE_ *fp);
void fflush_(FILE_ *fp);

2、myfile.c

#include "myfile.h"
FILE_ *fopen_(const char *path_name, const char *mode)
{int flag = 0; // 文件打开方式if (strcmp("w", mode) == 0){flag = flag | O_CREAT | O_WRONLY | O_TRUNC;}else if (strcmp("r", mode) == 0){flag = flag | O_RDONLY;}else if (strcmp("a", mode) == 0){flag = flag | O_APPEND | O_WRONLY | O_CREAT;}int id = 0; // 文件描述符if (flag & O_RDONLY)id = open(path_name, flag);elseid = open(path_name, flag, 0666);if (id == -1){// 打开失败收集打印错误信息const char *err = strerror(errno);write(2, err, strlen(err));return NULL;}// FILE结构体初始化FILE_ *fp = (FILE_ *)malloc(sizeof(FILE_));fp->flags = SYNC_LINE; // 默认设置为行刷新fp->fileno = id;fp->size = 0;fp->cap = SIZE;memset(fp->buffer, 0, SIZE);return fp;
}
void fwrite_(const void *ptr, int num, FILE_ *fp)
{memcpy(fp->buffer + fp->size, ptr, num);fp->size += num;if (fp->flags & SYNC_NOW){write(fp->fileno, fp->buffer, fp->size);fp->size = 0;}else if (fp->flags & SYNC_LINE){if (fp->buffer[fp->size - 1] == '\n'){write(fp->fileno, fp->buffer, fp->size);fp->size = 0;}}else if (fp->flags & SYNC_FULL){if (fp->size == fp->cap){write(fp->fileno, fp->buffer, fp->size);fp->size = 0;}}
}void fflush_(FILE_ *fp)
{if (fp->size > 0){write(fp->fileno, fp->buffer, fp->size);fsync(fp->fileno); // 将数据强制刷新至磁盘}
}
void fclose_(FILE_ *fp)
{fflush_(fp);close(fp->fileno);
}

(四)内核缓冲区

        其实上述的缓冲区是语言级别(封装在FILE结构体中)的缓冲区,在操作系统内核也存在一个缓冲区,其何时刷新由操作系统自主决定。

二、磁盘

(一)磁盘的存储

        一个磁盘拥有多个盘面,而在盘面上拥有多个磁道,不同盘面的相同磁道共同形成柱面,同时,磁盘被等分为多个扇形,而各个扇形称为扇区。

        磁盘在寻址时,基本单位为512字节。如图所示,绿色部分就是扇区,越靠近同心圆的扇区面积越小,越远离扇区的同心圆面积越大,但是每一个扇区的存储大小均为512字节。

        磁盘在寻址时,先有磁头摆动确定读写内容所在磁盘,再通过盘片高速旋转读写目标扇区。

        那如何在磁盘中定位指定扇区呢?实际上磁盘也有自己的地址:磁盘定位扇区通常使用CHS定位法,即磁道/柱面(cylinder)、定位磁头/盘面(head)、扇区(sector)

(二)磁盘的抽象存储结构

        当我们将不同盘面的磁盘顺序结合,其实我们可以将整个磁盘看作一个顺序存储的数组,这样对磁盘的管理,实际上就是对数组的管理,只要我们得到扇区的下标,即可定位磁盘上的扇区。而这样的管理方式的地址称为 LBA 地址。可以根据 LBA 地址映射到 CHS 地址,从而定位至指定扇区。

        将对上层的 LBA 地址和下层的 CHS 地址分开,便于操作系统管理磁盘,降低操作系统和磁盘的·耦合度,使得操作系统对磁盘的管理独立于磁盘。

(三)分页思想

        上述可知磁盘的最小单位是扇区512字节,但对于IO来讲,读写单位太小会导致频繁IO,因此操作系统的文件系统每次读取数据会以4KB为基本单位(大部分是4KB)读取至内存,无论用户修改多大的数据,操作系统也只会按照4KB为基本单位进行读写。

        根据局部性原理,当计算机访问某些数据时,它附近的数据也有非常大的概率被访问到,加载4KB有助于提高IO效率,同时增大缓存命中率。这个特点也印证了顺序表因顺序存储而缓存命中率高的优点,而链表因节点存储地址跳跃,缓存命中率低。

        操作系统中内存被划分成了一块块4KB大小的空间,每个空间被称为页框。

        磁盘中的空间也是按照4KB大小划分好的块。每个块被称为页帧

(四)磁盘的文件系统

1、概念

        按照上述,如果磁盘都只按照以4KB大小为基本单位进行管理,那么对于磁盘的文件系统来说,这个管理的方式十分的庞杂。

        实际上,磁盘采用分而治之的思想,例如将大小为500G的磁盘划分为4个125G进行管理,将125G又可以划分为多个5G进行管理。只要管理好5G大小的存储空间,即可管理好整个磁盘。

1、Super Block:存储文件系统的整体信息,如大小、块大小、空闲和已用块的数量等。在一个分区中超级块的数量不止一个,作用是备份。

2、GDT(Group Descriptor Table):块组描述表,它包含了该块组的元数据,如块组的起始块、可用块数等。

3、Block Bitmap:记录了块组内每个块的使用情况,位图中的每个位对应一个块,用0表示某位没有被使用,用1表示某位数据块已经被使用。

4、inode Bitmap:类似于块位图,但是用于记录inode节点的使用情况,用0表示某位没有被使用,用1表示某位inode已经被使用。

5、inode Table:保存了分组内部所有的可用(已使用+未使用)的inode。存储inode的数组,每个inode包含文件的元数据,如文件大小、权限、所有者、创建时间、inode号等。

        单个inode:存放文件中几乎所有的属性,如文件大小,所有者,最近修改时间等,唯独文件名不在inode表中存储。一个文件对应一个inode,inode是固定大小。每个分组中的inode为了区分彼此,它们都有自己的ID。同一分区 inode编号 是连续的,不同分区的 inode编号 没有任何关联。

        除了基本属性以外,inode 结构体中还含有一个 block[15] 数据块数组,该数组存储了其属于文件的数据块的指针,可通过该数组找到属于该文件的 Date Block 中的数据块。
6、Data blocks:实际存储文件数据的地方。文件数据被分散存储在不同的数据块中。

2、目录结构

        由上述所知,普通文件的属性存储在 inode节点 里,文件的内容存储在 Date Block 里。

        目录也属于文件,但目录的存储比较特殊。目录的属性依然存储与 inode 里,但目录的 Date Block 中存储的是所在目录下的文件的文件名与其 inode 编号的映射。对于用户来说,依靠 inode 编号区分文件十分困难,因此用户是通过文件名区分文件,而目录的 Date Block 中存储的是文件名与 inode编号 的映射关系,故可以通过文件名找到文件。这也是在同一目录下不能存在文件名相同的文件的原因。

3、新建、查找与删除文件

        对于新建文件,操作系统为该文件分配一个  inode节点 和若干 数据块,同时填充该文件的信息并将 inode节点 添加至 inode Table ,同时建立 inode节点 与 数据块 的映射(inode节点中的block数组)。之后修改 inode Bitmap 和 Date Bitmap,将文件名和inode编号的映射关系添加至目录的数据块中。

        对于查找文件,通过所在目录存储的文件名和 inode编号 的映射关系获取其 inode编号 。之后通过 inode Bitmap 查看该 inode编号 是否有效,若有效再通过该 inode编号 在 inode Table中寻找该 inode。通过该 inode 中的 block 数组即可获取该文件的数据块,之后通过 Date Bitmap 查看所用的数据块是否有效,若有效则查找文件成功。

        对于删除文件,通过所在目录存储的文件名和 inode编号 的映射关系获取其 inode编号 。通过查找 inode Table 获取其 inode节点,通过该节点获取并修改 inode Bitmap 和 Date Bitmap 为0。即逻辑删除并不清楚其真正的存储信息。

        上述可知 inode节点和数据块 的映射是存储在一个 block[15] 的数组里的,如果文件内容过大,应该如何存储呢?

        实际上数据块不仅可以存数据,也可以存储地址,也就是数据块也可以存储地址指向新的数据块。

        对于block[15]数组前12个下标中对应的数据块直接用于存储文件内容,数组后3个空间中存放的编号对应的数据块中存放了文件剩余数据的数据块编号。其中下标12是一级索引,它对应的数据块中存储的数据块编号直接用于存文件数据;下标13是二级索引,它对应的数据块中存储的数据块编号是一级索引;下标14是三级索引;逐级展开,能存储很大的文件。

三、软硬连接

(一)软链接

        1、概念

        软链接其实类似windows下的快捷方式,软链接相当于新建了一个文件,拥有自己独立的 inode节点与数据块,而其存储的内容为被链接文件的路径与文件名。

        2、软链接的建立删除

//建立软链接
ln -s 被链接文件 新建链接名称
//删除软链接
unlink 软链接名

(二)硬链接

        1、概念

        硬链接与软链接不同,硬链接并不是一个独立的文件。由上文我们知道,文件名和inode节点是一一对应的,而硬链接则是增加了文件名(硬链接)和inode节点的映射关系。

        2、硬链接的建立删除

//建立硬链接
ln 被链接文件 新建链接名称
//删除硬链接
unlink 硬链接名

        红框所圈出的数字为该文件被硬链接的数目。

        3、普通文件和目录文件的硬链接数

        当我们新建一个普通文件和目录文件时,我们可以发现两个文件的硬链接数并不相同。

         

        普通文件很好理解,因为文件本身的名字和 inode节点 就有映射关系,因此硬链接数为1。

        那为什么目录的硬链接数为2呢?实际是因为我们新建目录以后,系统会在目录里建立一个 .. 硬链接链接该目录,因此新建目录的硬链接数为2。为了防止破坏目录树形结构,因此系统不允许用户给目录建立硬链接。

四、动静态库

        查看可执行文件链接了哪些库:

ldd 可执行文件名

        查看可执行文件是动静态方法:

file 可执行文件名

(一)概念       

        静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。

        动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

        静态链接:在可执行文件生成前就把所需要的所有静态库链接在一起,一旦形成可执行程序便与静态库无关。

        静态链接不依赖第三方库,一旦形成可执行文件便独立于静态库,程序的可移植性好,但是形成的可执行文件体积巨大。

        动态链接:当程序在执行时才会加载所需要的库文件,程序在链接时并不会直接链接动态库,而是记录所需内容在动态库的相对位置(偏移量),只要在执行需要时再根据该相对位置将动态库加载至内存并取出所需内容。

        动态链接形成的可执行文件小,节省磁盘存储空间并且加载至内存速度快,但依赖动态库,程序的可移植性差。

(二)动静态库的建立使用

1、静态库

        当我们写好所需的程序后,分别将所有的 .c(.cpp)文件进行编译生成 .o 文件(链接文件),之后将所有的 .o(链接文件)进行打包归档即可。.h 文件告诉用户库的使用接口,而库本身是接口实现。

gcc -c Add.c    //生成Add.o文件
gcc -c Sub.c    //生成Sub.o文件
ar -rf libmath.a Add.o Sub.o    //生成名为math的静态库
ar -tv libmath.a    //查看静态库中的链接文件

        当我们生成好静态库以后,应该如何使用呢?这里我们新建目录模拟库的使用。

        

        当我们使用静态库时:

gcc test.c -o test -I ./lib/include/ -L ./lib/lib64/ -l math
-I:库的头文件所在目录;
-L:静态库所在目录;
-l:所使用静态库的名称;

        使用编译器提供的库并行不需要带这些选项,是因为编译器有自己的环境变量,能够找到位于/lib64库文件的存放目录和/usr/include头文件的存放目录。也可以将静态库和头文件放入这些目录或其他相关目录下,这就是一般软件的安装过程。

2、动态库

        当我们写好所需的程序后,分别将所有的 .c(.cpp)文件进行编译生成 .o 文件(链接文件),之后再使用gcc生成动态库即可。

gcc -fPIC -c Add.c Sub.c                 //生成动态库所需的.o文件
gcc -shared -o libmath.so Add.o Sub.o    //将.o文件生成动态库

        使用动静态库生成可执行文件的是相同,这里不进行赘述了。但是在执行上略不同。

        从上文我们可以知道,使用静态库生成可执行文件以后,该可执行文件独立于静态库了,可以直接执行;但是动态库在执行过程中是去动态库中寻找所需,可动态库生成的可执行文件的执行是由系统来做的,因此我们在执行动态库生成的可执行文件之前,还需要告诉系统所需的动态库的位置。

        下面有三种方案解决上述问题:

        (1)将动态库和头文件拷贝至对应的系统库路径和头文件路径下;

        (2)更改环境变量LD_LIBRARY_PATH,这个方法仅对本次登录有用;

export LD_LIBRARY_PATH=path_to_lib.so    /*动态库所在目录*/

        (3)配置ldconfig,这个方法永久生效

        /etc/ld.so.conf.d/是系统搜索动态库的路径

//进入/etc/ld.so.conf.d/后
sudo touch new.conf    //创建新配置文件
vim new.conf           //将动态库所在目录写入该配置文件
sudo ldconfig          //使配置文件生效

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

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

相关文章

SpringBoot(9)-Dubbo+Zookeeper

目录 一、了解分布式系统 二、RPC 三、Dubbo 四、SpringBootDubboZookeeper 4.1 框架搭建 4.2 实现RPC 一、了解分布式系统 分布式系统&#xff1a;由一组通过网络进行通信&#xff0c;为了完成共同的任务而协调工作的计算机节点组成的系统 二、RPC RPC&#xff1a;远程…

【Github】如何使用Git将本地项目上传到Github

【Github】如何使用Git将本地项目上传到Github 写在最前面1. 注册Github账号2. 安装Git工具配置用户名和邮箱仅为当前项目配置&#xff08;可选&#xff09; 3. 创建Github仓库4. 获取仓库地址5. 本地操作&#xff08;1&#xff09;进入项目文件夹&#xff08;2&#xff09;克隆…

Spring:Spring整合Mybatis开发之纯Mybatis开发

目前我们已经对Spring有一个简单的认识了&#xff1a; Spring有一个容器&#xff0c;叫做IoC容器&#xff0c;里面保存bean。 在进行企业级开发的时候&#xff0c;其实除了将自己写的类让Spring管理之外&#xff0c;还有一部分重要的工作就是使用第三方的技术。前面已经讲了如何…

大语言模型---LoRA中损失值的计算

文章目录 概要损失计算流程小结 概要 Llama-7B模型的LoRA微调训练中&#xff0c;通过使用Cross-Entropy Loss来度量模型输出的预测分布和真实标签分布之间的距离&#xff0c;来衡量模型的准确性。 本文主要介绍LoRA中损失值的计算流程。 Cross-Entropy Loss作用&#xff1a;是…

如何选择服务器

如何选择服务器 选择服务器时应考虑以下几个关键因素&#xff1a; 性能需求。根据网站的预期流量和负载情况&#xff0c;选择合适的处理器、内存和存储容量。考虑网站是否需要处理大量动态内容或高分辨率媒体文件。 可扩展性。选择一个可以轻松扩展的服务器架构&#xff0c;以便…

IT资产管理工具-NetBox

IT资产管理工具-NetBox 推荐一款IT资产管理工具 了解推荐阅读官方中文文档 https://docs.wangluohe.com/introduction/ 硬件要求 ​ - 建议4Core 8G以上&#xff0c;100G存储空间 这里我使用的Linux镜像为 CentOS8-Stream 提前关闭Selinux和防火墙 部署NetBox 一&#…

实战 | C#中使用YoloV8和OpenCvSharp实现目标检测 (步骤 + 源码)

导 读 本文主要介绍在C#中使用YoloV8实现目标检测,并给详细步骤和代码。 详细步骤 【1】环境和依赖项。 需先安装VS2022最新版,.NetFramework8.0,然后新建项目,nuget安装 YoloSharp,YoloSharp介绍: https://github.com/dme-compunet/YoloSharp 最新版6.0.1,本文…

Java基于Spring Boot框架的房屋租赁系统,附源码

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

C语言:深入理解指针

一.内存和地址 我们知道计算机上CPU&#xff08;中央处理器&#xff09;在处理数据的时候&#xff0c;需要的数据是在内存中读取的&#xff0c;处理后的数据也会放回内存中&#xff0c;那我们买电脑的时候&#xff0c;电脑上内存是 8GB/16GB/32GB 等&#xff0c;那这些内存空间…

Excel求和如何过滤错误值

一、问题的提出 平时&#xff0c;我们在使用Excel时&#xff0c;最常用的功能就是求和了&#xff0c;一说到求和你可能想到用sum函数&#xff0c;但是如果sum的求和区域有#value #Div等错误值怎么办&#xff1f;如下图&#xff0c;记算C列中工资的总和。 直接用肯定会报错&…

(Keil)MDK-ARM各种优化选项详细说明、实际应用及拓展内容

参考 MDK-ARM各种优化选项详细说明、实际应用及拓展内容 本文围绕MDK-ARM优化选项,以及相关拓展知识(微库、实际应用、调试)进行讲述,希望对你今后开发项目有所帮助。 1 总述 我们所指的优化,主要两方面: 1.代码大小(Size) 2.代码性能(运行时间) 在MDK-ARM中,优…

监控报警系统的指标、规则与执行闭环

随笔 从千万粉丝“何同学”抄袭开源项目说起&#xff0c;为何纯技术死路一条&#xff1f; 数据源的统一与拆分 监控报警系统的指标、规则与执行闭环 java 老矣&#xff0c;尚能饭否&#xff1f; 一骑红尘妃子笑&#xff0c;无人知是荔枝来! 有所依 我们如何知道系统交易…

【数据分享】2024年我国省市县三级的住宿服务设施数量(8类住宿设施/Excel/Shp格式)

宾馆酒店、旅馆招待所等住宿服务设施的配置情况是一个城市公共基础设施完善程度的重要体现&#xff0c;一个城市住宿服务设施种类越丰富&#xff0c;数量越多&#xff0c;通常能表示这个城市的公共服务水平越高&#xff01; 本次我们为大家带来的是我国各省份、各地级市、各区…

Hive离线数仓结构分析

Hive离线数仓结构 首先&#xff0c;在数据源部分&#xff0c;包括源业务库、用户日志、爬虫数据和系统日志&#xff0c;这些都是数据的源头。这些数据通过Sqoop、DataX或 Flume 工具进行提取和导入操作。这些工具负责将不同来源的数据传输到基于 Hive 的离线数据仓库中。 在离线…

搜索引擎中广泛使用的文档排序算法——BM25(Best Matching 25)

在搜索场景中&#xff0c;BM25能计算每个文档与查询的匹配度&#xff0c;从中找出最相关的文档&#xff0c;并按相关性高低排序展示。 要理解BM25&#xff0c;需要掌握以下几个关键概念&#xff1a; 1. 词频&#xff08;Term Frequency, TF&#xff09;&#xff1a;某关键词在文…

TCP socket api详解

文章目录 netstat -nltpaccept简单客户端工具 telnet 指定服务连接connect异常处理version 1 单进程版version 2 多进程版version 3 -- 多线程版本version 4 ---- 线程池版本 应用-简单的翻译系统服务器细节write 返回值 客户端守护进程化前台和后台进程的原理Linux的进程间关系…

HP6心率血压传感器

目录 一、介绍 1、工作原理概述 2、具体实现步骤 二、HP6的通信及配置 1、通信接口 2、器件地址/命令 3、校验 三、程序设计 ①IIC通信相关基础函数 ②HP6相关基础函数 一、介绍 HP6心率血压传感器的原理主要基于光电容积脉搏波描记法&#xff08;PPG&#xff09;&…

鸿蒙开发-音视频

Media Kit 特点 一般场合的音视频处理&#xff0c;可以直接使用系统集成的Video组件&#xff0c;不过外观和功能自定义程度低Media kit&#xff1a;轻量媒体引擎&#xff0c;系统资源占用低支持音视频播放/录制&#xff0c;pipeline灵活拼装&#xff0c;插件化扩展source/demu…

java: spire.pdf.free 9.12.3 create pdf

可以用windows 系统中文字体&#xff0c;也可以从文件夹的字体文件 /*** encoding: utf-8* 版权所有 2024 ©涂聚文有限公司* 许可信息查看&#xff1a;言語成了邀功盡責的功臣&#xff0c;還需要行爲每日來值班嗎* 描述&#xff1a;* # Author : geovindu,Geovin Du 涂…

【TEST】Apache JMeter + Influxdb + Grafana

介绍 使用Jmeter发起测试&#xff0c;测试结果存入Influxdb&#xff0c;Grafana展示你的测试结果。 环境 windows 10docker desktopJDK17 安装 Apache JMeter 访问官网&#xff08;Apache JMeter - Apache JMeter™&#xff09;下载JMeter&#xff08;目前最新版本5.6.3&a…