操作系统实验 实验3 存储器分配与回收
1.实验目的
了解动态分区分配方式中使用的数据结构和分配算法,并进一步加深动态分区存储管理方式及其实现过程的理解。
2.实验要求
用C语言实现首次适应算法的动态分区分配过程alloc()和回收过程free()。
一、实验内容:
1.实验内容
用C语言实现首次适应算法的动态分区分配过程alloc()和回收过程free()。其中,空闲分区通过空闲区说明表;在进行内存分配时,系统优先使用空闲区低端的空间。
(1)相关知识及其分析
当有一个新作业要求装入主存时,必须查空闲区说明表,从中找一个满足作业大小要求的低址空闲区。有时找到的空闲区可能大于作业需求量,这时应将该空闲区的低地址部分分配给请求作业,另一部分仍作为空闲区留在空闲区表中,以利于大作业的装入。
为了便于实现首次适应算法,在空闲区表中,按空闲区首址从低到高进行登记。为了保证快速查找,要不断地对表格进行紧缩,即让“空表目”项留在表的后部。空闲说明表如表2所示。
其分配/回收流程图参见本书第4章图4.7,4.8所示。
实验代码如下:#include <stdio.h> #include <iostream> #define N 5 using namespace std; // 定义一个结构体freearea,用于表示空闲区 // startaddress表示空闲区始址 // size表示空闲区大小 // state表示空闲区状态,0为空表目,1为可用空闲块 struct freearea {int startaddress;int size;int state; };// 定义全局变量freeblock,是一个包含N个freearea结构体的数组 // 初始化freeblock数组,设置各个空闲区的起始地址、大小和状态 struct freearea freeblock[N] = { {20, 20, 1}, {80, 50, 1}, {150, 100, 1}, {300, 30, 0}, {600, 100, 1} };// 内存分配函数,applyarea为作业申请的内存量 // 使用首次适应算法,遍历空闲区表寻找合适的空闲区进行分配 int alloc(int applyarea) {int i;// 遍历空闲区表for (i = 0; i < N; i++) {// 如果当前空闲区状态为可用(state为1)且大小大于等于申请量if (freeblock[i].state == 1 && freeblock[i].size >= applyarea) {// 记录当前空闲区的起始地址int allocated_start = freeblock[i].startaddress;// 如果空闲区大小大于申请量,分割空闲区if (freeblock[i].size > applyarea) {// 调整剩余空闲区的起始地址freeblock[i].startaddress += applyarea;// 调整剩余空闲区的大小freeblock[i].size -= applyarea;}// 如果空闲区大小恰好等于申请量,将其状态设置为空表目(state为0)else {freeblock[i].state = 0;}// 返回分配的内存起始地址return allocated_start;}}// 没有找到合适的空闲区,返回-1表示分配失败return -1; }// 内存回收函数,用于将释放的内存重新加入空闲区表 void setfree() {int s, l, i, j;// 提示用户输入释放区的开始地址printf("input free area startaddress:\n");// 读取用户输入的释放区的开始地址if (scanf("%d", &s) != 1) {// 处理输入错误的情况,这里简单提示输入错误并清空输入缓冲区printf("Invalid input for startaddress. Please enter a valid integer.\n");while (getchar() != '\n');return;}// 提示用户输入释放区的大小printf("input free area size:\n");if (scanf("%d", &l) != 1) {// 处理输入错误的情况,这里简单提示输入错误并清空输入缓冲区printf("Invalid input for size. Please enter a valid integer.\n");while (getchar() != '\n');return;}// 清除输入缓冲区中的换行符,避免影响后续输入while (getchar() != '\n');// 初始化插入位置为0int insert_pos = 0;// 找到释放区应插入的位置(按起始地址排序)while (insert_pos < N && freeblock[insert_pos].state == 1&& freeblock[insert_pos].startaddress < s)insert_pos++;// 检查前一个空闲区的索引,如果存在且状态为可用,则记录其索引,否则设为-1int prev_index = (insert_pos > 0 && freeblock[insert_pos - 1].state == 1)? insert_pos - 1 : -1;// 检查后一个空闲区的索引,如果存在且状态为可用,则记录其索引,否则设为-1int next_index = (insert_pos < N && freeblock[insert_pos].state == 1)? insert_pos : -1;// 如果前一个空闲区存在且其结束地址等于释放区的开始地址if (prev_index != -1 && freeblock[prev_index].startaddress + freeblock[prev_index].size == s) {// 合并到前一个空闲区,增加前一个空闲区的大小freeblock[prev_index].size += l;// 如果后一个空闲区存在且释放区的结束地址等于后一个空闲区的开始地址if (next_index != -1 && s + l == freeblock[next_index].startaddress) {// 合并三个空闲区(前一个+释放区+后一个)freeblock[prev_index].size += freeblock[next_index].size;// 将后一个空闲区标记为空表目freeblock[next_index].state = 0;}}// 如果后一个空闲区存在且释放区的结束地址等于后一个空闲区的开始地址else if (next_index != -1 && s + l == freeblock[next_index].startaddress) {// 合并到后一个空闲区,更新后一个空闲区的起始地址和大小freeblock[next_index].startaddress = s;freeblock[next_index].size += l;}// 如果不与任何空闲区相邻else {// 遍历空闲区表for (j = 0; j < N; j++) {// 找到一个空表目if (freeblock[j].state == 0) {// 将释放区信息填入空表目freeblock[j].startaddress = s;freeblock[j].size = l;// 将该表目状态设置为可用freeblock[j].state = 1;break;}}} }// 调整空闲区表函数,使空闲区按起始地址升序排列,空表目放在最后面 void adjust() {int i, j, swapped;struct freearea middata;// 第一阶段:使用冒泡排序按起始地址升序排列可用空闲区for (i = 0; i < N - 1; i++) {// 标记本次循环是否进行了交换操作swapped = 0;// 遍历未排序的空闲区for (j = 0; j < N - i - 1; j++) {// 如果当前和下一个空闲区都为可用,且当前空闲区起始地址大于下一个空闲区起始地址if (freeblock[j].state == 1 && freeblock[j + 1].state == 1 &&freeblock[j].startaddress > freeblock[j + 1].startaddress) {// 交换两个空闲区的信息middata = freeblock[j];freeblock[j] = freeblock[j + 1];freeblock[j + 1] = middata;// 标记进行了交换操作swapped = 1;}}// 如果本次循环没有进行交换操作,说明已经有序,提前结束排序if (!swapped) break;}// 第二阶段:将空表目移到表的末尾for (i = 0; i < N - 1; i++) {// 遍历未排序的空闲区for (j = 0; j < N - i - 1; j++) {// 如果当前空闲区为空表目,下一个空闲区为可用if (freeblock[j].state == 0 && freeblock[j + 1].state == 1) {// 交换两个空闲区的信息middata = freeblock[j];freeblock[j] = freeblock[j + 1];freeblock[j + 1] = middata;}}} }// 打印空闲区表函数,以表格形式输出当前所有空闲区的信息 void print() {int i;// 打印表格头部横线printf(" |---------------------------------------------------------------|\n");// 打印表格头部标题printf(" | start size state |\n");// 打印表格头部横线printf(" |---------------------------------------------------------------|\n");// 遍历空闲区表for (i = 0; i < N; i++) {// 打印每个空闲区的起始地址、大小和状态printf(" | %3d %3d %3d |\n",freeblock[i].startaddress, freeblock[i].size, freeblock[i].state);// 打印表格行分隔横线printf(" |---------------------------------------------------------------|\n");} }// 主函数,程序的入口点 int main() {int applyarea, start;char end;// 提示用户是否有作业请求内存printf("\n is there any job request memory? y or n:");// 主循环:处理多个作业的内存请求while ((end = getchar()) == 'y' || end == 'Y') {// 输出提示信息,说明当前空闲内存情况printf("at first the free memory is this:\n");// 调整空闲区表,确保按序排列adjust();// 打印当前空闲区状态print();// 提示用户输入作业请求的内存大小printf("input request memory size:");// 读取用户输入的作业请求的内存大小if (scanf("%d", &applyarea) != 1) {// 处理输入错误的情况,这里简单提示输入错误并清空输入缓冲区printf("Invalid input for applyarea. Please enter a valid integer.\n");while (getchar() != '\n');continue;}// 调用内存分配函数,获取分配的内存起始地址start = alloc(applyarea);// 调整空闲区表adjust();// 输出提示信息,说明分配后的空闲内存情况printf("after allocation, the free memory is this:\n");// 打印分配后的空闲区状态print();// 如果分配失败(返回值为-1)if (start == -1)// 输出提示信息,说明没有合适的内存printf("there is no fit memory, please wait\n");else {// 输出作业的内存起始地址printf("job's memory start address is:%d\n", start);// 输出作业的大小printf("job size is:%d\n", applyarea);// 输出提示信息,说明作业正在运行printf("job is running.\n");// 输出提示信息,说明作业已终止printf("job is terminated.\n");// 调用内存回收函数setfree();// 调整空闲区表adjust();// 输出提示信息,说明内存回收后的空闲内存情况printf("after memory recovery, the free memory is this:\n");// 打印回收后的空闲区状态print();}// 提示用户是否有其他作业等待printf("is there any job that is waiting? y or n:");}// 程序正常结束,返回0return 0; }
二、实验过程及结果记录
情况一:成功分配内存且空闲区大小大于申请量
初始空闲区状态如输出所示,请求 30 大小的内存,从起始地址 80 的空闲区分配,该空闲区大小为 50 大于申请量,分割后剩余大小为 20 。
作业运行并终止后,输入释放区地址 80 和大小 30 ,内存回收后空闲区恢复初始状态。
情况二:成功分配内存且空闲区大小等于申请量
请求 20 大小的内存,从起始地址 20 的空闲区分配,该空闲区大小等于申请量,分配后该空闲区状态设为 0 。
作业运行并终止后,用户输入释放区地址 20 和大小 20 ,内存回收后空闲区恢复初始状态。
情况三:分配内存失败
修改部分:
修改代码在 adjust 函数中,使用冒泡排序将空闲区按起始地址升序排列,并将空表目移到表的末尾。代码中使用 swapped 标记是否进行了交换操作,提前结束排序以提高效率。而原代码也进行了类似的排序和移动空表目操作,但没有使用 swapped 标记提前结束排序。
原代码:
void adjust(){int i,j;struct freearea middata;for(i=0;i<N;i++) /*将空闲区按始地址顺序在表中排列*/for(j=0;j<N;j++)if(freeblock[j].startaddress>freeblock[j+1].startaddress){middata.startaddress=freeblock[j].startaddress;middata.size=freeblock[j].size;middata.state=freeblock[j].state;freeblock[j].startaddress=freeblock[j+1].startaddress;freeblock[j].size=freeblock[j+1].size;freeblock[j].state=freeblock[j+1].state;freeblock[j+1].startaddress=middata.startaddress;freeblock[j+1].size=middata.size;freeblock[j+1].state=middata.state;}for(i=0;i<N;i++) /*将空表目放在表后面*/for(j=0;j<N;j++)if(freeblock[j].state==0&&freeblock[j+1].state==1){middata.startaddress=freeblock[j].startaddress;middata.size=freeblock[j].size;middata.state=freeblock[j].state;freeblock[j].startaddress=freeblock[j+1].startaddress;freeblock[j].size=freeblock[j+1].size;freeblock[j].state=freeblock[j+1].state;freeblock[j+1].startaddress=middata.startaddress;freeblock[j+1].size=middata.size;freeblock[j+1].state=middata.state;}}
修复代码:
// 第一阶段:使用冒泡排序按起始地址升序排列可用空闲区for (i = 0; i < N - 1; i++) {// 标记本次循环是否进行了交换操作swapped = 0;// 遍历未排序的空闲区for (j = 0; j < N - i - 1; j++) {// 如果当前和下一个空闲区都为可用,且当前空闲区起始地址大于下一个空闲区起始地址if (freeblock[j].state == 1 && freeblock[j + 1].state == 1 &&freeblock[j].startaddress > freeblock[j + 1].startaddress) {// 交换两个空闲区的信息middata = freeblock[j];freeblock[j] = freeblock[j + 1];freeblock[j + 1] = middata;// 标记进行了交换操作swapped = 1;}}// 如果本次循环没有进行交换操作,说明已经有序,提前结束排序if (!swapped) break;} // 调整空闲区表函数,使空闲区按起始地址升序排列,空表目放在最后面 void adjust() {int i, j, swapped;struct freearea middata;// 第一阶段:使用冒泡排序按起始地址升序排列可用空闲区for (i = 0; i < N - 1; i++) {// 标记本次循环是否进行了交换操作swapped = 0;// 遍历未排序的空闲区for (j = 0; j < N - i - 1; j++) {// 如果当前和下一个空闲区都为可用,且当前空闲区起始地址大于下一个空闲区起始地址if (freeblock[j].state == 1 && freeblock[j + 1].state == 1 &&freeblock[j].startaddress > freeblock[j + 1].startaddress) {// 交换两个空闲区的信息middata = freeblock[j];freeblock[j] = freeblock[j + 1];freeblock[j + 1] = middata;// 标记进行了交换操作swapped = 1;}}// 如果本次循环没有进行交换操作,说明已经有序,提前结束排序if (!swapped) break;}// 第二阶段:将空表目移到表的末尾for (i = 0; i < N - 1; i++) {// 遍历未排序的空闲区for (j = 0; j < N - i - 1; j++) {// 如果当前空闲区为空表目,下一个空闲区为可用if (freeblock[j].state == 0 && freeblock[j + 1].state == 1) {// 交换两个空闲区的信息middata = freeblock[j];freeblock[j] = freeblock[j + 1];freeblock[j + 1] = middata;}}} }
三、实 验 小 结
心得体会:
在本次关于存储器分配与回收的实验中,我通过用 C 语言实现首次适应算法的动态分区分配过程 alloc () 和回收过程 free (),对动态分区存储管理方式有了更深入的理解和实践体验,同时也在编程技能和问题分析能力方面得到了锻炼,收获颇丰。
从知识掌握角度来看,通过实验,我清晰地认识到动态分区分配方式中数据结构和分配算法的工作原理。空闲区说明表作为管理空闲内存的关键数据结构,其记录的起始地址、长度和状态信息,为内存的分配与回收提供了重要依据。首次适应算法优先使用空闲区低端空间的策略,让我明白了如何高效地利用内存资源,在实际操作中,我体会到这种算法的优势在于尽可能地保留高端的大空闲区,为后续大作业的装入创造条件。同时,在实现内存回收时,处理空闲区合并的逻辑,使我对内存空间的连续化管理有了更深刻的认识,理解了如何避免内存碎片的产生。
在编程实践方面,本次实验极大地提升了我的代码编写和调试能力。在实现 alloc () 函数时,通过遍历空闲区表并根据作业需求进行空闲区的分配和分割,锻炼了我对循环结构和条件判断语句的运用能力;而 free () 函数中复杂的空闲区合并逻辑,涉及到多个条件判断和索引操作,让我学会如何在复杂的业务逻辑中保持清晰的思路。此外,在调试过程中,我遇到了如数组越界、输入错误处理不完善等问题,通过逐步排查和分析,最终解决了这些问题,这一过程让我掌握了许多实用的调试技巧,也培养了我耐心和细致的编程习惯。
不过,这次实验也暴露出我存在的一些不足。一方面,在代码优化上还有很大的提升空间。例如,在调整空闲区表顺序的 adjust () 函数中,虽然最终实现了功能,但代码的效率和简洁性仍有待提高。即使使用冒泡排序并添加了 swapped 标记提前结束排序,冒泡排序在数据量较大时效率较低,后续可以学习和尝试更高效的排序算法,如快速排序或归并排序,以提升程序性能。另一方面,在处理用户输入时,虽然进行了基本的错误处理,但对于一些异常情况的考虑还不够全面,输入验证的健壮性有待加强。
总的来说,本次实验是一次非常有意义的实践活动,不仅巩固了课堂所学的理论知识,还让我在实际操作中发现问题、解决问题,积累了宝贵的经验。在今后的学习中,我会更加注重知识的实际应用,不断提升自己的编程水平和解决复杂问题的能力,为深入学习操作系统及其他计算机专业知识打下坚实的基础。
相关文章:
操作系统实验 实验3 存储器分配与回收
1.实验目的 了解动态分区分配方式中使用的数据结构和分配算法,并进一步加深动态分区存储管理方式及其实现过程的理解。 2.实验要求 用C语言实现首次适应算法的动态分区分配过程alloc()和回收过程free()。 一、实验内容: 1.实验内容 用C语言实…...
408考研逐题详解:2009年第13题
2009年第13题 浮点数加、减运算过程一般包括对阶、尾数运算、规格化、舍入和判溢出等步骤。设浮点数的阶码和尾数均采用补码表示,且位数分别为 5 位和 7 位(均含 2 位符号位)。若有两个数 X 2 7 29 / 32 X2^7\times29/32 X2729/32, Y 2 …...
什么是虚拟同步发电机
虚拟同步发电机(Virtual Synchronous Generator, VSG) 是一种基于电力电子技术的先进控制策略,通过模拟传统同步发电机的机电特性和动态行为,使逆变器或储能系统能够像传统发电机一样为电网提供惯性支撑、频率调节和电压稳定性支持…...
性能比拼: Linkerd vs. Istio
本内容是对知名性能评测博主 Anton Putra Linkerd vs. Istio (Rust vs. C) performance benchmark 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准 在本内容中,我们将对比 Kubernetes 服务网格中的 Istio 和 Linkerd。 相关代码详见 github 我们将运行…...
FPGA: Xilinx Kintex 7实现PCIe接口
在Xilinx Kintex-7系列FPGA上实现PCIe(Peripheral Component Interconnect Express)接口,通常使用Xilinx提供的7 Series Integrated Block for PCIe IP核,结合Vivado设计流程。以下是实现PCIe接口的详细步骤和关键点,适…...
《Effective Python》第2章 字符串和切片操作——Python 字符串格式化的现代选择f-strings
引言 本篇博客基于学习《Effective Python》第三版 Chapter 2: Strings and Slicing 的 Item 11 “Prefer Interpolated F-Strings Over C-style Format Strings and str.format” 的总结与延伸。 字符串格式化是 Python 编程中的常见操作,用于动态生成可读性高的…...
vue 去掉右边table的下拉条与下面的白色边框并补充满
::v-deep table {width: 100% !important; } ::v-deep .el-table::after, .el-table::before {display: none !important; }/* 隐藏滚动条但保留滚动功能 */ ::v-deep .el-table__body-wrapper::-webkit-scrollbar {width: 0 !important;height: 0 !important; }::v-deep .el-t…...
RabbitMq消息阻塞,立即解决方案
如果目前你的 RabbitMQ 消费者 被卡住不再消费消息,且消息已经到达消费者绑定队列,但Spring Cloud Stream 没有继续触发 StreamListener 的方法执行。这类问题一般是因为消费者线程阻塞或消息被 RabbitMQ 拒绝投递。我们可以按照下面的步骤紧急处理&…...
单片机-STM32部分:14、SPI
飞书文档https://x509p6c8to.feishu.cn/wiki/VYYnwOc9Zi6ibFk36lYcPQdRnlf 什么是SPI SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola(摩托罗拉)首先在其MC68HCXX系列处理器上定义的。 SPI,是一种高速的&…...
Selenium-Java版(操作元素)
选择和操控元素的基本方法 前言 选择元素 选择元素的方法 根据 id属性选择元素 根据class属性选择元素 根据tag名选择元素 通过WebElement对象选择元素 示例 等待界面元素出现 原因 解决 操控元素 点击元素 输入框 获取元素信息 获取元素文本内容 获取…...
20052012世界银行中国企业调查数据-社科数据
2005&2012世界银行中国企业调查数据-社科数据https://download.csdn.net/download/paofuluolijiang/90623828https://download.csdn.net/download/paofuluolijiang/90623828 世界银行中国企业调查数据(World Bank Enterprise Surveys Data)是国际金…...
学习黑客NFC技术详解
NFC技术详解:近距离通信的无线桥梁 📱💳 学习目标:了解NFC技术的基本原理、应用场景及安全注意事项,掌握这一日益普及的近场通信技术 1. NFC的概念与基础 📡 NFC(Near Field Communication&…...
Java问题排查常用命令行工具速查表
Java问题排查常用命令行工具速查表 工具典型用途常用命令示例说明/场景jps列出本机所有Java进程jps -l获取Java进程PID和主类名,配合其它工具使用jcmd动态诊断、堆heap dump、线程dump等jcmd helpjcmd VM.flagsjcmd GC.heap_infojcmd Thread.print功能最全…...
近期搬了个家,停更了几天,明天继续哈~
近期搬了个家,停更了几天,明天继续哈~ 近期搬家比较离谱,第一天下暴雨,冰雹,停电,第二天又停电两小时,截止14号晚上11:30终于完工 了,从西二的20 号楼到西三的19号楼&am…...
C#高级编程:IO和序列化
在 C# 编程中,输入输出(IO)和序列化是两个至关重要的概念,它们为数据的存储、读取以及在不同环境间的传输提供了强大的支持。无论是开发小型应用程序,还是构建复杂的企业级系统,深入理解并熟练运用 IO 和序列化技术都是必不可少的。 一、C# 中的 IO 基础 1、文件流…...
PyQt5完整指南:从入门到实践
引言 PyQt5是Python编程语言的一个GUI(图形用户界面)工具包,它是Qt5应用程序框架的Python绑定。Qt是一个跨平台的C应用程序开发框架,被广泛用于开发GUI程序和非GUI程序。PyQt5让Python开发者能够使用Python语言享受到Qt框架的强大…...
C#高级编程:加密解密
在数字化时代,数据安全是每个应用程序都必须重视的环节。无论是用户的个人信息、敏感的商业数据,还是重要的系统配置,都需要得到妥善的保护。C# 作为一种广泛应用的编程语言,提供了丰富且强大的加密解密功能,帮助开发者构建安全可靠的应用。本文将深入探讨 C# 高级编程中的…...
银行卡真伪验证助力金融合规-银行卡实名认证接口
在数字化时代,金融交易日益频繁,用户身份与银行卡信息的真实性核验成为保障资金安全、防止欺诈行为的关键环节。无论是在线支付、网络借贷、电商平台,还是社交软件、金融服务APP,均需对用户的银行卡进行严格的实名认证。为满足企业…...
html5+css3实现傅里叶变换的动态展示效果(仅供参考)
<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>傅里叶变换的动态展示效果</title><sty…...
SysConfig修改后`ti_msp_dl_config`文件未更新问题的解决方法(已解决)
SysConfig修改后ti_msp_dl_config文件未更新问题的解决方法 在使用SysConfig工具配置TI MSPM0系列MCU时,有时会遇到一个令人困惑的问题:在SysConfig中修改配置后,生成的ti_msp_dl_config.c文件内容却没有更新。这可能会导致工程无法正确编译…...
深入浅出 IPFS 在 DApps 和 NFT 中的应用:以 Pinata 实战为例
目录 IPFS背景什么是 IPFS?IPFS 在 DApps 与 NFT 中的作用什么是 Pinata?为什么使用它?使用原生IPFS上传下载文件(HTML + JavaScript 示例)使用Pinata上传下载文件(HTML + JavaScript 示例)注册并创建APIKey使用 Pinata 上传文件和JSON(HTML + JavaScript 示例)总结IP…...
深度剖析LLM的“大脑”:单层Transformer的思考模式探索
简单说一下哈 —— 咱们打算训练一个单层 Transformer 加上稀疏自编码器的小型百万参数大型语言模型(LLM),然后去调试它的思考过程,看看这个 LLM 的思考和人类思考到底有多像。 LLMs 是怎么思考的呢? 开源 LLM 出现之后…...
(4)python开发经验
文章目录 1 使用ctypes库调用2 使用pybind11 更多精彩内容👉内容导航 👈👉Qt开发 👈👉python开发 👈 1 使用ctypes库调用 说明:ctypes是一个Python内置的库,可以提供C兼容的数据类型…...
卷积神经网络全连接层详解:特征汇总、FCN替代与性能影响分析
【内容摘要】 本文聚焦卷积神经网络(CNN)的全连接层,详细介绍其将二维特征图转化为一维向量的过程,阐述全卷积网络(FCN)如何通过转置卷积替代全连接层以实现像素级分类,并分析全连接层对图像分类…...
通义千问-langchain使用构建(一)
目录 序言通义千问1获取通义千问api_key2Conda构建下本地环境3 构建一下多轮对话 LangChain1使用Langchain调用通义千问接口实现翻译 结论 序言 25年5月,现在基本每个大厂都有涉及大模型(Large Language Model),然后在大模型基础上构建应用框架。 参考…...
六西格玛觉醒:一场数据思维的启蒙运动
当生产线上的不良品率曲线第一次在我眼前具象化为统计波动图时,我意识到自己正站在新旧认知的断层带上。从对着MINITAB界面手足无措的菜鸟,到能独立完成过程能力分析的绿带学员,这段学习旅程不仅重塑了我的问题解决逻辑,更让我…...
BitMart合约交易体验 BitMart滑点全赔的底层逻辑
美国新泽西州泽西市,2025年5月13日 – BitMart,全球领先的数字资产交易平台,推出了其开创性的滑点保护计划,旨在解决加密市场中最具挑战性且常常被忽视的风险之一:滑点。该计划为交易者提供了在 USDT 保证金永续合约交…...
HCIP(BFD)
一、前言 随着网络应用的广泛部署,网络发生故障极大可能导致业务异常。为了减小链路、设备故障对业 务的影响,提高网络的可靠性,网络设备需要尽快检测到与相邻设备间的通信故障,以便及时采取措施,保证业务正常进行。BFD(Bidirectional Forwarding Detection,双向转发检测)提供…...
json-server的用法-基于 RESTful API 的本地 mock 服务
json-server 是一个非常方便的工具,用于快速搭建基于 RESTful API 的本地 mock 服务,特别适合前端开发阶段模拟后端数据接口。 🧩 一、安装 npm install -g json-server🚀 二、快速启动 创建一个 db.json 文件(模拟数…...
化工单元操作试验装置系列产品JG-SX211计算机过程控制板框过滤操作实训装置
化工单元操作试验装置系列产品JG-SX211计算机过程控制板框过滤操作实训装置 一、装置功能 板框过滤岗位技能:板框过滤机的构造和操作方法;板框压滤机的操作(装合、过滤、洗涤、卸渣、整理);洗涤速率与最终过滤速率的关…...
Linux 内核 IPv4 协议栈中的协议注册机制解析
1. 引言 在 Linux 内核的 IPv4 协议栈中,inetsw 是一个核心数据结构,负责管理不同套接字类型(如 SOCK_STREAM、SOCK_DGRAM)的协议实现。本文结合代码分析,深入探讨其设计原理、动态协议注册机制及并发安全实现。 2. inetsw 的结构与作用 2.1 定义与初始化 static struc…...
【PostgreSQL数据分析实战:从数据清洗到可视化全流程】附录-C. 常用SQL脚本模板
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 附录C. 常用SQL脚本模板速查表一、数据清洗与预处理模板二、数据聚合与分析模板三、窗口函数应用模板四、性能优化与监控模板五、数据备份与恢复模板六、权限管理与安全模板…...
Linux操作系统实战:中断源码的性能分析(转)
Linux中断是指在Linux操作系统中,当硬件设备或软件触发某个事件时,CPU会中断正在执行的任务,并立即处理这个事件。它是实现实时响应和处理外部事件的重要机制,Linux中断可以分为两种类型:硬件中断和软件中断࿰…...
Windows系统Anaconda/Miniconda的安装、配置、基础使用、清理缓存空间和Pycharm/VSCode配置指南
本文同步发布在个人博客: Windows系统Anaconda/Miniconda的安装、配置、基础使用、清理缓存空间和Pycharm/VSCode配置指南 - 萑澈的寒舍Conda 是一个开源的跨平台包管理与环境管理工具,广泛应用于数据科学、机器学习及 Python 开发领域。它不仅能帮助用…...
用HBuilder运行小程序到微信开发者工具
首先在HBuilder里配置微信开发者工具安装路径 “运行”--“运行到小程序模拟器”--“运行设置”--“微信开发者工具路径”...
基于网关实现不同网段S7-1200 CPU的通信方法
在工业自动化场景中,不同网段的S7-1200 PLC之间需要进行数据交换时,通常需要借助网关或路由设备实现跨网段通信。以下是几种常见的实现方法及详细配置步骤。 一、通信需求分析 当两个或多个S7-1200 PLC位于不同子网(如192.168.1.0/24和192.1…...
微信小程序学习之轮播图swiper
轮播图是小程序的重要组件,我们还是好好学滴。 1、上代码,直接布局一个轮播图组件(index.wxml): <swiper class"swiper" indicator-active-color"#fa2c19" indicator-color"#fff" duration"{{durati…...
零基础用 Hexo + Matery 搭建博客|Github Pages 免费部署教程
文章目录 一、Hexo1.1 依赖1.2 快速使用1.3 目录说明1.4 命令说明1.4.1 常规命令1.4.2 全局选项 二、主题安装2.1 安装 Matery 主题2.1.1 下载2.1.2 配置2.1.2.1 基础配置2.1.2.2 新建页面类型2.1.2.3 其他配置 2.2 其他主题推荐 三、部署3.1 部署到 Github Pages 四、总结 一、…...
Large-Scale Language Models: In-Depth Principles and Pioneering Innovations
大规模语言模型(Large-Scale Language Models, LLMs)是人工智能领域的璀璨明珠,深刻重塑了自然语言处理(NLP)并推动多模态应用的蓬勃发展。从BERT的语义洞察到GPT系列的生成奇迹,再到Grok、LLaMA等模型的跨界创新,LLMs在智能对话、代码生成、科学探索等领域展现出近乎人…...
微信小程序智能商城系统(uniapp+Springboot后端+vue管理端)
一、系统介绍 本智能商城系统是基于当今主流技术栈开发的一款多端商城解决方案,主要包括微信小程序前端、SpringBoot 后端服务以及 Vue 管理后台三大部分。系统融合了线上商城的核心功能,支持商品浏览、下单、支付、订单管理等操作,适用于中小…...
命令行快速上传文件到SFTP服务器(附参考示例)
一、SFTP基础命令格式 更新参数后的标准命令格式为: sftp -P [端口号] [用户名][服务器IP]:[远程路径] <<< $put [本地文件路径]二、新参数实例解析 使用新连接参数的完整命令示例: sftp -P 30033 test_jigou_sftp121.199.64.216:/download…...
【Linux】第十六章 分析和存储日志
1. RHEL 日志文件保存在哪个目录中? 一般存储在 /var/log 目录中。 2. 什么是syslog消息和非syslog消息? syslog消息是一种标准的日志记录协议和格式,用于系统和应用程序记录日志信息。它规定了日志消息的结构和内容,包括消息的…...
vue2+ThinkPHP5实现简单大文件切片上传
使用 Vue 2 和 ThinkPHP 5 实现大文件切片上传功能 文章目录 一、前端(Vue 2)安装依赖文件上传并切片全部代码二、后端(ThinkPHP 5)完整代码一、前端(Vue 2) 安装依赖 安装spark-md5依赖 用于生成文件哈希,以便验证文件的完整性。 npm install spark-md5文件上传并切…...
phpstudy的Apache添加AddType application/x-httpd-php .php .php5配置无效的处理方式
前言 最近在学习安全竞赛ctf相关的内容,使用phpstudy作为服务端,研究图片上传相关漏洞的靶场upload-labs。其中遇到后缀名过滤,会过滤后缀名php。按照网上的处理方式,只需要在Apache服务器的配置文件中增加“AddType application…...
2025年Flutter项目管理技能要求
在2025年,随着Flutter技术的广泛应用和项目复杂度的提升,项目管理的重要性愈发凸显。Flutter项目管理不仅需要技术能力,还需要良好的沟通、协调、规划和执行能力。本文将详细探讨2025年Flutter项目管理应具备的技能要求,帮助项目管…...
Step1
项目 SchedulerSim 已搭建完成 ✅ ⸻ ✅ 你现在拥有的: • 🔧 两种调度器(Round Robin SJF) • 📦 模拟进程类 Process • 🧱 清晰结构:OOP 风格 便于扩展 • ✍️ 主函数已演示调度器运行效…...
MCP(一)——QuickStart
目录 1. MCP简介2. MCP的优势3. MCP核心4. QuickStart For Server Developers(仅具参考)4.1 MCP核心概念4.2 构建MCP服务器的代码4.2.1 设置MCP服务器实例4.2.2 辅助函数4.2.3 实现工具执行4.2.4 在Cherry-Studio中添加MCP服务器4.2.5 演示4.2.5.1 测试工具get_alerts4.2.5.2 测…...
NLP的基本流程概述
自然语言处理(Natural Language Processing, NLP)是计算机科学与人工智能领域中的一个重要分支,旨在使计算机能够理解、分析、生成和处理人类语言。NLP的基本流程通常包括以下几个关键步骤: 1. 文本预处理 (Text Preprocessing) …...
【Java学习笔记】==运算符
运算符 是一个比较运算符 既可以判断基本类型,又可以判断引用类型 如果判断基本类型,判断的是值是否相等,示例: int i 10; double d 10.0(底层会发生自动类型转换) 如果判断引用类型,判断的是地址是否相…...
移动网页调试工具实战:从 Chrome 到 WebDebugX 的效率演进
前端开发的日常,说白了就是构建、预览、调试的不断循环。如果是桌面浏览器,调试体验已经极致成熟;但一旦牵涉到移动端,尤其是 WebView 环境,一切都变得复杂。 过去几年里,我陆续试用了多个调试工具&#x…...