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

模拟内存管理

文章目录

  • 1. 实验六:内存管理
  • 2. 记录内存空间使用情况
    • 2.1 全局参数
    • 2.2 内存空间相关参数
    • 2.3 关键结构体定义
    • 2.4 内存系统初始化
  • 3. 记录空闲分区
    • 3.1 采用位图的方式记录物理内存中的空闲帧
      • 3.1.1 记录方式
      • 3.1.2 举例分析
    • 3.2 主要操作
      • 3.2.1 初始化空闲帧:
      • 3.2.2 分配帧时标记:
      • 3.2.3 释放帧时标记:
  • 4. 内存分配算法(段页式 + 页级 First‑Fit)
    • 4.1 分配算法原理
    • 4.2 主要函数
      • 4.2.1 `allocate_for_process(process_id, num_pages)`
      • 4.2.2 `allocate_segment(int seg_id, int num_pages)`
    • 4.2 内存分配源代码
  • 5. 内存释放算法
    • 5.1 算法设计
      • 5.1.1 算法流程
      • 5.1.2 函数调用链
      • 5.1.3 关键代码部分
    • 5.2 内存释放源代码
  • 6. 测试
    • 6.1 产生测试数据
      • 6.1.1 关键代码:随机为5个进程分别分配和释放内存15次,即随机产生15组数据:(进程Pi 分配内存大小) 或者 (进程Pi结束)
      • 6.1.2 测试程序设计
    • 6.2 输出结果分析
      • 6.2.1 部分输出结果
      • 6.2.2 具体分析
        • 6.2.2.1 逐步说明
          • (1)操作 5:为进程 P1 分配 2 页内存
          • (2)操作 6:为进程 P2 分配 3 页内存
          • (3)操作 7:释放进程 P1 的内存
          • (4)操作 8:为进程 P0 分配 2 页内存
        • 6.2.2.1 总结表格
    • 6.3 测试程序源代码
  • 7.源代码与完整测试结果
    • 7.1 源代码
    • 7.2 完整测试结果
  • 8.参考链接
    • 【操作系统-75】段页式管理方式
    • 操作系统——内存段式和段页式管理

1. 实验六:内存管理

2. 记录内存空间使用情况

2.1 全局参数

宏定义名称数值含义/单位作用说明
PAGE_SIZE4096字节(4KB)每页的大小,模拟操作系统中的分页单位。常用于计算内存大小。
NUM_PAGES16模拟的物理内存总共被划分成的页数(即帧数),表示系统最多有16个可分配的物理页框。
NUM_SEGMENTS5系统最多同时支持的段数。每个段对应一个页表,用于段页式管理。
PHYS_MEM_SIZEPAGE_SIZE * NUM_PAGES = 65536字节(64KB)模拟的物理内存总大小,实际用于申请内存空间 phys_mem
NUM_PROCESSES5个进程同时最多允许存在的进程数量。每个进程在本模型中最多只拥有一个段。
NUM_OPERATIONS15在模拟过程中将执行的随机内存操作数量(包括分配和释放)。

2.2 内存空间相关参数

  • 段表 segment_table[]:保存每段的页表指针 (page_table) 与段长 (limit)。
  • 页表 PageTableEntry[]:保存页是否有效 (valid) 及映射的物理帧号 (frame_number)。
  • 进程‑段-映射 process_segments[]:下标 = 进程 ID,值 = 该进程占用的段号 (‑1 表示未分配)。
    这三张表共同描述“哪一帧属于哪一段、哪一段属于哪个进程”,即可完整反映“已用/空闲”。

2.3 关键结构体定义

// 页表条目
typedef struct
{int valid;int frame_number;
} PageTableEntry;// 段表条目
typedef struct {int base;                 // 段起始页,本例固定 0int limit;                // 段长(页数)PageTableEntry *page_table;
} SegmentTableEntry;SegmentTableEntry segment_table[NUM_SEGMENTS];
int process_segments[NUM_PROCESSES];  // -1 表未分配
  • SegmentTableEntry:每个段记录其起始位置(base)、页数(limit)、指向页表的指针。
  • PageTableEntry:页表记录每页是否有效(valid)及其对应的物理帧号(frame_number)。

2.4 内存系统初始化

void init_memory()
{phys_mem = (char *)malloc(PHYS_MEM_SIZE);memset(phys_mem, 0, PHYS_MEM_SIZE);for (int i = 0; i < NUM_PAGES; i++)free_frames[i] = 1;for (int i = 0; i < NUM_SEGMENTS; i++)segment_table[i].page_table = NULL;// 初始化进程段记录为-1(表示未分配)for (int i = 0; i < NUM_PROCESSES; i++)process_segments[i] = -1;
}
代码功能说明
phys_mem = malloc(...)分配一块用于模拟的物理内存空间(64KB)。
memset(...)将分配的物理内存内容清零,确保起始干净状态。
for (i < NUM_PAGES) free_frames[i] = 1初始化帧表,每一帧设为“空闲”。
for (i < NUM_SEGMENTS) page_table = NULL初始化段表,表示系统还没有被分配的段。
for (i < NUM_PROCESSES) process_segments = -1初始化进程段记录,表示每个进程当前没有段。

3. 记录空闲分区

3.1 采用位图的方式记录物理内存中的空闲帧

3.1.1 记录方式

free_frames[i] == 1 表示第 i帧空闲;0 表示已占用。

int free_frames[NUM_PAGES]; // NUM_PAGES = 16

这是一个长度为 16 的整数数组,**每一位对应一个物理帧(页框)**的状态。

  • free_frames[i] == 1:第 i 个页框是空闲的。
  • free_frames[i] == 0:第 i 个页框是已分配的。
  • 初始化全置 1;分配时置 0;释放时再置 1。

3.1.2 举例分析

如果当前有如下内存状态:

free_frames = { 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 };

则代表:

  • 空闲页框:1号、4号、5号、6号、8号、9号、10号、11号、13号、14号、15号
  • 已占用帧:0号、2号、3号、7号、12号

当分配新帧时,函数 allocate_frame() 会顺序扫描并返回第一个为 1 的下标(即空闲帧的位置)。

int allocate_frame()
{for (int i = 0; i < NUM_PAGES; i++){if (free_frames[i]){free_frames[i] = 0;return i;}}return -1; // 没有空闲帧
}

3.2 主要操作

3.2.1 初始化空闲帧:

for (int i = 0; i < NUM_PAGES; i++)free_frames[i] = 1;

3.2.2 分配帧时标记:

if (free_frames[i]) {free_frames[i] = 0; // 标记为占用return i;
}

3.2.3 释放帧时标记:

free_frames[segment_table[seg_id].page_table[i].frame_number] = 1;

4. 内存分配算法(段页式 + 页级 First‑Fit)

4.1 分配算法原理

  1. 找空段:线性扫描段表,寻找 page_table==NULL 的条目。
  2. 逐页分配物理帧:对所需页数调用 allocate_frame();该函数顺序扫描位图找到第一张空闲帧(First‑Fit),并把对应位图位置置 0。
  3. 失败回滚:若中途无帧可用,则把已分到的帧全部归还并释放刚创建的页表。
  4. 记录映射:成功后,将进程 ID 对应的 process_segments[pid] 设为刚找到的段号。

4.2 主要函数

4.2.1 allocate_for_process(process_id, num_pages)

函数设计逻辑

给指定进程分配一个段,并在该段内分配一定页数的内存。

  • 自动选择一个空闲段
  • 利用 allocate_segment() 进行段页式分配
  • 更新进程段占用记录

举例说明

假设进程 P1 请求分配 3 页内存:

allocate_for_process(1, 3);

如果 P1 没有分配过内存,系统会:

  1. 找一个空闲段(比如段 2)
  2. 给这个段分配 3 个页,每页对应一个物理帧
  3. segment_table[2] 中建立页表
  4. process_segments[1] = 2 记录下来

如果之后再调用同样的函数为 P1 分配,因其已占用段,函数将返回 -1(失败)


4.2.2 allocate_segment(int seg_id, int num_pages)

项目内容说明
函数名allocate_segment()
功能为指定段分配一张页表,并为该段的每一页分配一个物理帧
成功返回0
失败返回-1(非法段号、段已使用、内存不足)
失败后的回滚机制会释放已分配帧和页表,避免内存泄漏或段状态异常
PageTableEntry *pt = (PageTableEntry *)malloc(sizeof(PageTableEntry) * num_pages);// 分配页表空间
for (int i = 0; i < num_pages; i++) {//为每一页分配物理帧 + 填写页表int frame = allocate_frame();...pt[i].valid = 1;pt[i].frame_number = frame;
}
  • 为这个段动态分配一个页表数组 pt,大小为 num_pagesPageTableEntry
  • 每个 PageTableEntry 用来记录一页的状态,包括:
    • 该页是否有效 (valid)
    • 该页对应的物理帧号 (frame_number)

失败时释放已分配帧并回滚:

for (int j = 0; j < i; j++)free_frames[pt[j].frame_number] = 1;
free(pt);

4.2 内存分配源代码

int allocate_frame() {                  // First‑Fitfor (int i = 0; i < NUM_PAGES; ++i)if (free_frames[i]) { free_frames[i] = 0; return i; }return -1;                          // 无空闲帧
}int allocate_segment(int seg,int pages){PageTableEntry *pt = malloc(sizeof(PageTableEntry)*pages);for (int i = 0; i < pages; ++i){int frame = allocate_frame();if (frame == -1){               // 回滚for (int j = 0; j < i; ++j) free_frames[pt[j].frame_number] = 1;free(pt); return -1;}pt[i].valid = 1; pt[i].frame_number = frame;}segment_table[seg].limit = pages;segment_table[seg].page_table = pt;return 0;
}int allocate_for_process(int pid,int pages){if (process_segments[pid] != -1) return -1;        int seg = find_free_segment();                     if (seg == -1) return -1;if (allocate_segment(seg,pages) == 0){             process_segments[pid] = seg;                   return 0;}return -1;
}
  • 每个进程最多分配一个段。
  • 每个段内部通过页表映射页到物理帧。
  • 页分配按需调用 allocate_frame() 逐个寻找空闲帧。

5. 内存释放算法

5.1 算法设计

5.1.1 算法流程

(1)调用 free_process_memory(process_id)

(2)如果该进程有段(process_segments[pid] != -1):

  • 获取段号 seg_id
  • 调用 free_segment(seg_id) 释放段

(3)在 free_segment(seg_id) 中:

  • 遍历该段页表中的每个有效页
  • 将页表中记录的帧号释放(free_frames[frame] = 1
  • 释放页表内存,清空段表项

​ 综述:当进程释放内存时,需释放段中所有有效页,并更新位图。先根据 process_segments[pid] 找到该进程占用的段号,后遍历该段的页表:把每个 valid 页对应的 free_frames[frame_number] 置 1,再释放页表内存,最后清空段表项 (page_table=NULL, limit=0);将进程‑段映射改回 ‑1


5.1.2 函数调用链

free_process_memory(process_id) → free_segment(seg_id)

5.1.3 关键代码部分

free_segment()

for (int i = 0; i < segment_table[seg_id].limit; i++) {if (segment_table[seg_id].page_table[i].valid)free_frames[segment_table[seg_id].page_table[i].frame_number] = 1; // 标记帧为空闲
}
free(segment_table[seg_id].page_table); // 释放页表
segment_table[seg_id].page_table = NULL;
segment_table[seg_id].limit = 0;

free_process_memory()

if (process_segments[process_id] != -1) {free_segment(process_segments[process_id]);process_segments[process_id] = -1; // 清除进程段映射
}

5.2 内存释放源代码

void free_segment(int seg){if (segment_table[seg].page_table == NULL) return;for (int i = 0; i < segment_table[seg].limit; ++i)if (segment_table[seg].page_table[i].valid)free_frames[segment_table[seg].page_table[i].frame_number] = 1;free(segment_table[seg].page_table);          // 释放页表segment_table[seg].page_table = NULL;segment_table[seg].limit = 0;
}void free_process_memory(int pid){int seg = process_segments[pid];if (seg != -1){free_segment(seg);                        process_segments[pid] = -1;               }
}

6. 测试

6.1 产生测试数据

6.1.1 关键代码:随机为5个进程分别分配和释放内存15次,即随机产生15组数据:(进程Pi 分配内存大小) 或者 (进程Pi结束)

// 生成随机操作序列
for (int i = 0; i < NUM_OPERATIONS; i++)
{operations[i].op_type = rand() % 2;                // 0: 分配, 1: 释放operations[i].process_id = rand() % NUM_PROCESSES; // 进程ID: 0-4operations[i].page_count = rand() % 4 + 1;         // 分配1-4页operations[i].result = 0;                          // 初始化结果
}

6.1.2 测试程序设计

  1. 随机操作生成:生成15次随机操作,包括进程内存分配和释放
  2. 进程管理:通过process_segments数组记录每个进程使用的段
  3. 内存布局可视化print_memory_layout()函数可以直观显示帧的使用情况
  4. 详细日志:记录每次操作的详细信息和结果
  5. 分析中断:在执行4组操作后,提供选择是否继续执行剩余操作

6.2 输出结果分析

6.2.1 部分输出结果

操作  5: 为进程 P1 分配 2 页内存...
分配成功! 进程 P1 使用段 1
空闲帧: 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P1  |
| 帧  3: 进程 P1  |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  6: 为进程 P2 分配 3 页内存...
分配失败! 原因: 进程已有分配的内存
空闲帧: 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P1  |
| 帧  3: 进程 P1  |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  7: 释放进程 P1 的内存...
释放成功! 段 1 已释放
空闲帧: 2 3 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 空闲    |
| 帧  3: 空闲    |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  8: 为进程 P0 分配 2 页内存...
分配成功! 进程 P0 使用段 1
空闲帧: 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+

6.2.2 具体分析

6.2.2.1 逐步说明

(1)操作 5:为进程 P1 分配 2 页内存
  • 成功:P1 使用段 1
  • 系统为 P1 分配了 2 个物理帧
  • 已使用帧:01(P2)、23(P1)

内存布局:

| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P1  |
| 帧  3: 进程 P1  |
| 帧  4~15: 空闲   |

(2)操作 6:为进程 P2 分配 3 页内存
  • 失败:提示“进程已有分配的内存”
  • 因为 P2 之前已经使用段分配了内存(帧 0、1),不能重复分配
  • 所以内存状态 无变化

内存布局:保持和操作5相同


(3)操作 7:释放进程 P1 的内存
  • 成功释放段 1
  • 释放了帧 2 和 3
  • 空闲帧更新为:234~15

内存布局更新:

| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 空闲    |
| 帧  3: 空闲    |
| 帧  4~15: 空闲   |

(4)操作 8:为进程 P0 分配 2 页内存
  • 成功:P0 使用段 1(刚刚 P1 释放后,段 1 被回收)
  • 系统为 P0 分配 2 个帧,从空闲帧中分配:帧 2 和 3

内存布局更新:

| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4~15: 空闲   |

6.2.2.1 总结表格
操作编号操作类型成功/失败内存变化描述
操作 5P1 分配 2 页成功占用帧 2、3,段 1 被 P1 占用
操作 6P2 再次分配 3 页失败P2 已有内存分配,操作无效,内存不变
操作 7P1 释放内存成功释放段 1,帧 2、3 被回收
操作 8P0 分配 2 页成功重用段 1,P0 分配帧 2、3

6.3 测试程序源代码

int main()
{// 初始化随机数生成器srand(time(NULL));init_memory();printf("初始化完成\n");print_memory_status();print_memory_layout();// 生成随机操作序列for (int i = 0; i < NUM_OPERATIONS; i++){operations[i].op_type = rand() % 2;                // 0: 分配, 1: 释放operations[i].process_id = rand() % NUM_PROCESSES; // 进程ID: 0-4operations[i].page_count = rand() % 4 + 1;         // 分配1-4页operations[i].result = 0;                          // 初始化结果}// 执行操作序列printf("\n开始测试随机操作序列...\n");for (int i = 0; i < NUM_OPERATIONS; i++){Operation *op = &operations[i];if (op->op_type == 0){ // 分配内存printf("\n操作 %2d: 为进程 P%d 分配 %d 页内存...\n",i + 1, op->process_id, op->page_count);op->result = allocate_for_process(op->process_id, op->page_count);if (op->result == 0){printf("分配成功! 进程 P%d 使用段 %d\n",op->process_id, process_segments[op->process_id]);}else{printf("分配失败! 原因: ");if (process_segments[op->process_id] != -1){printf("进程已有分配的内存\n");}else{printf("内存不足或没有空闲段\n");}}}else{ // 释放内存printf("\n操作 %2d: 释放进程 P%d 的内存...\n",i + 1, op->process_id);if (process_segments[op->process_id] != -1){int segment = process_segments[op->process_id];free_process_memory(op->process_id);printf("释放成功! 段 %d 已释放\n", segment);op->result = 0;}else{printf("释放失败! 进程 P%d 没有分配的内存\n", op->process_id);op->result = -1;}}print_memory_status();print_memory_layout();}// 清理资源for (int i = 0; i < NUM_PROCESSES; i++){free_process_memory(i);}free(phys_mem);return 0;
}

7.源代码与完整测试结果

7.1 源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>#define PAGE_SIZE 4096 // 4KB
#define NUM_PAGES 16   // 16页
#define NUM_SEGMENTS 5 // 5
#define PHYS_MEM_SIZE (PAGE_SIZE * NUM_PAGES)
#define NUM_PROCESSES 5 // 5
#define NUM_OPERATIONS 15// 模拟物理内存
char *phys_mem;// 页表条目
typedef struct
{int valid;int frame_number;
} PageTableEntry;// 段表条目
typedef struct
{int base;int limit;PageTableEntry *page_table;
} SegmentTableEntry;SegmentTableEntry segment_table[NUM_SEGMENTS];// 记录空闲帧
int free_frames[NUM_PAGES];// 进程占用段的记录
int process_segments[NUM_PROCESSES];// 创建一个操作日志结构
typedef struct
{int op_type;    // 0: 分配, 1: 释放int process_id; // 进程IDint page_count; // 分配的页数(仅当op_type=0时有效)int result;     // 操作结果: 0成功,-1失败
} Operation;// 存储操作日志
Operation operations[NUM_OPERATIONS];void init_memory()
{phys_mem = (char *)malloc(PHYS_MEM_SIZE);memset(phys_mem, 0, PHYS_MEM_SIZE);for (int i = 0; i < NUM_PAGES; i++)free_frames[i] = 1;for (int i = 0; i < NUM_SEGMENTS; i++)segment_table[i].page_table = NULL;// 初始化进程段记录为-1(表示未分配)for (int i = 0; i < NUM_PROCESSES; i++)process_segments[i] = -1;
}int allocate_frame()
{for (int i = 0; i < NUM_PAGES; i++){if (free_frames[i]){free_frames[i] = 0;return i;}}return -1; // 没有空闲帧
}// 分段 + 分页 分配
int allocate_segment(int seg_id, int num_pages)
{if (seg_id >= NUM_SEGMENTS || segment_table[seg_id].page_table != NULL)return -1;PageTableEntry *pt = (PageTableEntry *)malloc(sizeof(PageTableEntry) * num_pages);for (int i = 0; i < num_pages; i++){int frame = allocate_frame();if (frame == -1){printf("内存不足,释放已分配帧\n");for (int j = 0; j < i; j++)free_frames[pt[j].frame_number] = 1;free(pt);return -1;}pt[i].valid = 1;pt[i].frame_number = frame;}segment_table[seg_id].base = 0;segment_table[seg_id].limit = num_pages;segment_table[seg_id].page_table = pt;return 0;
}// 释放段
void free_segment(int seg_id)
{if (seg_id >= NUM_SEGMENTS || segment_table[seg_id].page_table == NULL)return;for (int i = 0; i < segment_table[seg_id].limit; i++){if (segment_table[seg_id].page_table[i].valid)free_frames[segment_table[seg_id].page_table[i].frame_number] = 1;}free(segment_table[seg_id].page_table);segment_table[seg_id].page_table = NULL;segment_table[seg_id].limit = 0;
}void print_memory_status()
{printf("空闲帧: ");for (int i = 0; i < NUM_PAGES; i++){if (free_frames[i])printf("%d ", i);}printf("\n");
}// 打印内存布局示意图
void print_memory_layout()
{printf("内存布局示意图:\n");printf("+-----------------+\n");for (int i = 0; i < NUM_PAGES; i++) // 确保这个循环只执行NUM_PAGES次{printf("| 帧 %2d: ", i);if (free_frames[i]){printf("空闲    |\n");}else{// 查找该帧属于哪个段/进程int found = 0;for (int s = 0; s < NUM_SEGMENTS && !found; s++) // 添加!found条件优化{if (segment_table[s].page_table != NULL){for (int p = 0; p < segment_table[s].limit && !found; p++) // 添加!found条件优化{if (segment_table[s].page_table[p].valid &&segment_table[s].page_table[p].frame_number == i){// 找到对应的进程IDfor (int proc = 0; proc < NUM_PROCESSES; proc++){if (process_segments[proc] == s){printf("进程 P%d  |\n", proc);found = 1;break;}}}if (found)break;}}}if (!found){printf("已占用   |\n");}}}printf("+-----------------+\n");
}// 为进程分配内存
int allocate_for_process(int process_id, int num_pages)
{// 如果进程已经有分配的段,则返回失败if (process_segments[process_id] != -1){return -1;}// 寻找一个空闲段int seg_id = -1;for (int i = 0; i < NUM_SEGMENTS; i++){if (segment_table[i].page_table == NULL){seg_id = i;break;}}if (seg_id == -1){return -1; // 没有空闲段}int result = allocate_segment(seg_id, num_pages);if (result == 0){// 分配成功,记录进程占用的段process_segments[process_id] = seg_id;}return result;
}// 释放进程内存
void free_process_memory(int process_id)
{if (process_segments[process_id] != -1){free_segment(process_segments[process_id]);process_segments[process_id] = -1;}
}int main()
{// 初始化随机数生成器srand(time(NULL));init_memory();printf("初始化完成\n");print_memory_status();print_memory_layout();// 生成随机操作序列for (int i = 0; i < NUM_OPERATIONS; i++){operations[i].op_type = rand() % 2;                // 0: 分配, 1: 释放operations[i].process_id = rand() % NUM_PROCESSES; // 进程ID: 0-4operations[i].page_count = rand() % 4 + 1;         // 分配1-4页operations[i].result = 0;                          // 初始化结果}// 执行操作序列printf("\n开始测试随机操作序列...\n");for (int i = 0; i < NUM_OPERATIONS; i++){Operation *op = &operations[i];if (op->op_type == 0){ // 分配内存printf("\n操作 %2d: 为进程 P%d 分配 %d 页内存...\n",i + 1, op->process_id, op->page_count);op->result = allocate_for_process(op->process_id, op->page_count);if (op->result == 0){printf("分配成功! 进程 P%d 使用段 %d\n",op->process_id, process_segments[op->process_id]);}else{printf("分配失败! 原因: ");if (process_segments[op->process_id] != -1){printf("进程已有分配的内存\n");}else{printf("内存不足或没有空闲段\n");}}}else{ // 释放内存printf("\n操作 %2d: 释放进程 P%d 的内存...\n",i + 1, op->process_id);if (process_segments[op->process_id] != -1){int segment = process_segments[op->process_id];free_process_memory(op->process_id);printf("释放成功! 段 %d 已释放\n", segment);op->result = 0;}else{printf("释放失败! 进程 P%d 没有分配的内存\n", op->process_id);op->result = -1;}}print_memory_status();print_memory_layout();}// 清理资源for (int i = 0; i < NUM_PROCESSES; i++){free_process_memory(i);}free(phys_mem);return 0;
}

7.2 完整测试结果

PS C:\Users\23370\Desktop\os> ./test_1
初始化完成
空闲帧: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
内存布局示意图:
+-----------------+
| 帧  0: 空闲    |
| 帧  1: 空闲    |
| 帧  2: 空闲    |
| 帧  3: 空闲    |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+开始测试随机操作序列...操作  1: 为进程 P2 分配 2 页内存...
分配成功! 进程 P2 使用段 0
空闲帧: 2 3 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 空闲    |
| 帧  3: 空闲    |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  2: 为进程 P3 分配 1 页内存...
分配成功! 进程 P3 使用段 1
空闲帧: 3 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P3  |
| 帧  3: 空闲    |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  3: 为进程 P3 分配 3 页内存...
分配失败! 原因: 进程已有分配的内存
空闲帧: 3 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P3  |
| 帧  3: 空闲    |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  4: 释放进程 P3 的内存...
释放成功! 段 1 已释放
空闲帧: 2 3 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 空闲    |
| 帧  3: 空闲    |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  5: 为进程 P1 分配 2 页内存...
分配成功! 进程 P1 使用段 1
空闲帧: 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P1  |
| 帧  3: 进程 P1  |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  6: 为进程 P2 分配 3 页内存...
分配失败! 原因: 进程已有分配的内存
空闲帧: 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P1  |
| 帧  3: 进程 P1  |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  7: 释放进程 P1 的内存...
释放成功! 段 1 已释放
空闲帧: 2 3 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 空闲    |
| 帧  3: 空闲    |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  8: 为进程 P0 分配 2 页内存...
分配成功! 进程 P0 使用段 1
空闲帧: 4 5 6 7 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作  9: 为进程 P1 分配 4 页内存...
分配成功! 进程 P1 使用段 2
空闲帧: 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P2  |
| 帧  1: 进程 P2  |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4: 进程 P1  |
| 帧  5: 进程 P1  |
| 帧  6: 进程 P1  |
| 帧  7: 进程 P1  |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作 10: 释放进程 P2 的内存...
释放成功! 段 0 已释放
空闲帧: 0 1 8 9 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 空闲    |
| 帧  1: 空闲    |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4: 进程 P1  |
| 帧  5: 进程 P1  |
| 帧  6: 进程 P1  |
| 帧  7: 进程 P1  |
| 帧  8: 空闲    |
| 帧  9: 空闲    |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作 11: 为进程 P4 分配 4 页内存...
分配成功! 进程 P4 使用段 0
空闲帧: 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P4  |
| 帧  1: 进程 P4  |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4: 进程 P1  |
| 帧  5: 进程 P1  |
| 帧  6: 进程 P1  |
| 帧  7: 进程 P1  |
| 帧  8: 进程 P4  |
| 帧  9: 进程 P4  |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作 12: 释放进程 P3 的内存...
释放失败! 进程 P3 没有分配的内存
空闲帧: 10 11 12 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P4  |
| 帧  1: 进程 P4  |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4: 进程 P1  |
| 帧  5: 进程 P1  |
| 帧  6: 进程 P1  |
| 帧  7: 进程 P1  |
| 帧  8: 进程 P4  |
| 帧  9: 进程 P4  |
| 帧 10: 空闲    |
| 帧 11: 空闲    |
| 帧 12: 空闲    |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作 13: 为进程 P3 分配 3 页内存...
分配成功! 进程 P3 使用段 3
空闲帧: 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P4  |
| 帧  1: 进程 P4  |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4: 进程 P1  |
| 帧  5: 进程 P1  |
| 帧  6: 进程 P1  |
| 帧  7: 进程 P1  |
| 帧  8: 进程 P4  |
| 帧  9: 进程 P4  |
| 帧 10: 进程 P3  |
| 帧 11: 进程 P3  |
| 帧 12: 进程 P3  |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作 14: 释放进程 P1 的内存...
释放成功! 段 2 已释放
空闲帧: 4 5 6 7 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P4  |
| 帧  1: 进程 P4  |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 进程 P4  |
| 帧  9: 进程 P4  |
| 帧 10: 进程 P3  |
| 帧 11: 进程 P3  |
| 帧 12: 进程 P3  |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+操作 15: 为进程 P4 分配 1 页内存...
分配失败! 原因: 进程已有分配的内存
空闲帧: 4 5 6 7 13 14 15
内存布局示意图:
+-----------------+
| 帧  0: 进程 P4  |
| 帧  1: 进程 P4  |
| 帧  2: 进程 P0  |
| 帧  3: 进程 P0  |
| 帧  4: 空闲    |
| 帧  5: 空闲    |
| 帧  6: 空闲    |
| 帧  7: 空闲    |
| 帧  8: 进程 P4  |
| 帧  9: 进程 P4  |
| 帧 10: 进程 P3  |
| 帧 11: 进程 P3  |
| 帧 12: 进程 P3  |
| 帧 13: 空闲    |
| 帧 14: 空闲    |
| 帧 15: 空闲    |
+-----------------+

8.参考链接

【操作系统-75】段页式管理方式

操作系统——内存段式和段页式管理

相关文章:

模拟内存管理

文章目录 1. 实验六&#xff1a;内存管理2. 记录内存空间使用情况2.1 全局参数2.2 内存空间相关参数2.3 关键结构体定义2.4 内存系统初始化 3. 记录空闲分区3.1 采用位图的方式记录物理内存中的空闲帧3.1.1 记录方式3.1.2 举例分析 3.2 主要操作3.2.1 初始化空闲帧&#xff1a;…...

大模型调优方法与注意事项

大模型调优&#xff08;Fine-tuning&#xff09;是指对预训练的大型语言模型&#xff08;如GPT、BERT、LLaMA等&#xff09;进行二次训练&#xff0c;使其适应特定任务或领域的过程。以下是调优的关键步骤、方法和注意事项&#xff1a; 一、调优的核心步骤 任务定义与数据准备 …...

简易的考试系统设计(Web实验)

简易的考试系统设计&#xff08;Web实验&#xff09; 1.实验内容与设计思想&#xff08;一&#xff09;实验需求&#xff08;二&#xff09;设计思路 2.代码展示3.实验小结 1.实验内容与设计思想 &#xff08;一&#xff09;实验需求 1.编写两个页面程序&#xff0c;一个HTML…...

【嵌入式开发-SDIO】

嵌入式开发--SDIO ■ SDIO-简介■■■■■ ■ SDIO-简介 SDIO(Secure Digital Input and Output)&#xff0c;即安全数字输入输出接口。它是在SD卡接口的基础上发展而来&#xff0c;它可以兼容之前的SD卡&#xff0c;并可以连接SDIO接口设备&#xff0c;比如&#xff1a;蓝牙、…...

基于Kubernetes的Apache Pulsar云原生架构解析与集群部署指南(上)

#作者&#xff1a;闫乾苓 文章目录 概念和架构概述主要特点消息传递核心概念Pulsar 的消息模型Pulsar 的消息存储与分发Pulsar 的高级特性架构BrokerBookKeeperZooKeeper 概念和架构 概述 Pulsar 是一个多租户、高性能的服务器到服务器消息传递解决方案。Pulsar 最初由雅虎开…...

车载网络TOP20核心概念科普

一、基础协议与总线技术 CAN总线 定义&#xff1a;控制器局域网&#xff0c;采用差分信号传输&#xff0c;速率最高1Mbps&#xff0c;适用于实时控制&#xff08;如动力系统&#xff09;。形象比喻&#xff1a;如同“神经系统”&#xff0c;负责传递关键控制信号。 LIN总线 定…...

使用JAVA对接Deepseek API实现首次访问和提问

一、标题 参考&#xff1a;https://www.cnblogs.com/saoge/p/18866776 使用JAVA对接Deepseek API实现首次访问和 提问&#xff1a;我有50万能做什么小本生意&#xff0c;举例3个! 二、代码 import java.io.BufferedReader; import java.io.InputStreamReader; import java.…...

【C语言】文件操作(续)

目录 复习&#xff1a; 一⽂件的顺序读写 例子&#xff1a; 前言&#xff1a; 在上篇文章中介绍了文件的类型&#xff0c;文件指针&#xff0c;流&#xff0c;操作的函数。 在本篇文章继续为大家带来文件细节分享&#xff0c;如 顺序读写等等。 复习&#xff1a; fopen是…...

基于CBOW模型的词向量训练实战:从原理到PyTorch实现

基于CBOW模型的词向量训练实战&#xff1a;从原理到PyTorch实现 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;词向量是将单词映射为计算机可处理的数值向量的重要方式。通过词向量&#xff0c;单词之间的语义关系能够以数学形式表达&#xff0c;为后续的文本分…...

mac连接lniux服务器教学笔记

从你的检查结果看&#xff0c;容器内已经安装了 XFCE 桌面环境&#xff08;xfce.desktop 和 xubuntu.desktop 的存在说明桌面环境已存在&#xff09;。以下是针对 Docker 容器环境的远程桌面配置方案&#xff1a; 一、容器内快速配置远程桌面&#xff08;XFCE VNC&#xff09;…...

vue3 - keepAlive缓存组件

在Vue 3中&#xff0c;<keep-alive>组件用于缓存动态组件或路由组件的状态&#xff0c;避免重复渲染&#xff0c;提升性能。 我们新建两个组件&#xff0c;在每一个组件里面写一个input&#xff0c;在默认情况下当组件切换的时候&#xff0c;数据会被清空&#xff0c;但…...

阀门产业发展方向报告(石油化工阀门应用技术交流大会)

本文大部分内容来自中国通用机械工业协会副会长张宗列在“2024全国石油化工阀门应用技术交流大会”上发表的报告。 一、国外阀门产业发展 从全球阀门市场分布看&#xff0c;亚洲是最大的工业阀门市场&#xff0c;美洲是全球第二大工业阀门市场&#xff0c;欧洲位列第三。 从国…...

Windows Server 2025 安装AMD显卡驱动

运行显卡驱动安装程序&#xff0c;会提示出问题。但是此时资源已经解压 来到驱动路径 C:\AMD\AMD-Software-Installer\Packages\Drivers\Display\WT6A_INF 打开配置文件&#xff0c;把这两行替换掉 %ATI% ATI.Mfg, NTamd64.10.0...16299, NTamd64.10.0, NTamd64.6.0, NTamd64.…...

用 CodyBuddy 帮我写自动化运维脚本

我正在参加CodeBuddy「首席试玩官」内容创作大赛&#xff0c;本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴”。 #CodeBuddy首席试玩官 背景 我个人是非常喜欢 Jenkins 自动化部署工具的&#xff0c;之前都是手写 Jenki…...

从单体到微服务:基于 ABP vNext 模块化设计的演进之路

&#x1f680; 从单体到微服务&#xff1a;基于 ABP vNext 模块化设计的演进之路 &#x1f9e9; 引言 在需求多变且性能压力日益增大的背景下&#xff0c;传统单体应用在部署、维护和扩展方面存在显著挑战。 ABP vNext 作为基于 ASP.NET Core 的框架&#xff0c;自带模块化设…...

USB集线器芯片革新之战:CH334U如何以工业级性能重新定义HUB控制器

一、当工业智能化遭遇接口瓶颈 在智能制造与边缘计算蓬勃发展的今天&#xff0c;工程师们正面临一个看似微小却至关重要的挑战——如何让USB集线器在极端工况下保持稳定&#xff1f;传统HUB控制器在-20℃以下频繁出现信号失真&#xff0c;产线突然断电导致的静电击穿更是让设备…...

C#学习7_面向对象:类、方法、修饰符

一、类 1class 1)定义类 访问修饰符class 类名{ 字段 构造函数&#xff1a;特殊的方法&#xff08;用于初始化对象&#xff09; 属性 方法... } eg: public class Person { // 字段 private string name; private int a…...

基于 Spring Boot 瑞吉外卖系统开发(十)

基于 Spring Boot 瑞吉外卖系统开发&#xff08;十&#xff09; 修改菜品 修改菜品是在原有的菜品信息的上对菜品信息进行更新&#xff0c;对此修改菜品信息之前需要将原有的菜品信息在修改界面进行展示&#xff0c;然后再对菜品信息进行修改。 修改菜品分为回显菜品信息和更…...

C++ 与 Lua 联合编程

在软件开发的广阔天地里&#xff0c;不同编程语言各有所长。C 以其卓越的性能、强大的功能和对硬件的直接操控能力&#xff0c;在系统开发、游戏引擎、服务器等底层领域占据重要地位&#xff0c;但c编写的程序需要编译&#xff0c;这往往是一个耗时操作&#xff0c;特别对于大型…...

中介者模式(Mediator Pattern)详解

文章目录 1. 中介者模式概述1.1 定义1.2 基本思想2. 中介者模式的结构3. 中介者模式的UML类图4. 中介者模式的工作原理5. Java实现示例5.1 基本实现示例5.2 飞机空中交通控制示例5.3 GUI应用中的中介者模式6. 中介者模式的优缺点6.1 优点6.2 缺点7. 中介者模式的适用场景8. 中介…...

Linux系统(OpenEuler22.03-LTS)部署FastGPT

在 openEuler 22.03 LTS 系统上通过 Docker Compose 安装 FastGPT 的步骤如下&#xff1a; 官方参考文档&#xff1a;https://doc.fastgpt.cn/docs/development/docker/ 1. 安装 Docker 和 Docker Compose 可以参考我之前离线安装Docker的文章&#xff1a;openEuler 22.03 LT…...

Kubernetes控制平面组件:Controller Manager 之 内置Controller详解

云原生学习路线导航页&#xff08;持续更新中&#xff09; kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计&#xff08;一&#xff09;Kubernetes架构原则和对象设计&#xff08;二&#xff09;Kubernetes架构原则和对象设计&#xff08;三&#xff09;Kubernetes控…...

结合Splash与Scrapy:高效爬取动态JavaScript网站

在当今的Web开发中&#xff0c;JavaScript的广泛应用使得许多网站的内容无法通过传统的请求-响应模式直接获取。为了解决这个问题&#xff0c;Scrapy开发者经常需要集成像Splash这样的JavaScript渲染引擎。本文将详细介绍Splash JS引擎的工作原理&#xff0c;并探讨如何将其与S…...

用于构建安全AI代理的开源防护系统

大家读完觉得有帮助记得及时关注&#xff01;&#xff01;&#xff01; 大型语言模型&#xff08;LLMs&#xff09;已经从简单的聊天机器人演变为能够执行复杂任务的自主代理&#xff0c;例如编辑生产代码、编排工作流程以及基于不受信任的输入&#xff08;如网页和电子邮件&am…...

算法与数据结构 - 常用图算法总结

在图论中&#xff0c;图算法非常重要&#xff0c;广泛应用于计算机科学、网络分析、社交网络、地理信息系统等领域。下面是一些常用的图算法&#xff0c;按不同功能和应用场景分类&#xff1a; 1. 图的遍历 图遍历算法用于遍历图中的节点和边。主要有两种常见的图遍历方法&am…...

克里金模型+多目标优化+多属性决策!Kriging+NSGAII+熵权TOPSIS!

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 克里金模型多目标优化多属性决策&#xff01;KrigingNSGAII熵权TOPSIS&#xff01;&#xff01;matlab2023b语言运行&#xff01; 1.克里金模型&#xff08;Kriging Model&#xff09;是一种基于空间统计学的插值方法…...

LLM 论文精读(三)Demystifying Long Chain-of-Thought Reasoning in LLMs

这是一篇2025年发表在arxiv中的LLM领域论文&#xff0c;主要描述了长思维链 Long Chain-of-Thought 对LLM的影响&#xff0c;以及其可能的生成机制。通过大量的消融实验证明了以下几点&#xff1a; 与shot CoT 相比&#xff0c;long CoT 的 SFT 可以扩展到更高的性能上限&…...

【Prompt工程—文生图】案例大全

目录 一、人物绘图 二、卡通头像 三、风景图 四、logo设计图 五、动物形象图 六、室内设计图 七、动漫风格 八、二次元图 九、日常场景图 十、古风神化图 十一、游戏场景图 十二、电影大片质感 本文主要介绍了12种不同类型的文生图技巧&#xff0c;通过加入不同的图像…...

本地可执行命令的智能体部署方案

本地可执行命令的智能体部署方案&#xff0c;目标是让大语言模型&#xff08;LLM&#xff09;在本地接收自然语言指令&#xff0c;并自动调用系统命令、脚本或应用程序&#xff0c;完成任务自动化。这类系统通常被称为 LLM Agent with Tool Use 或 本地 Agent 实体系统。 &…...

rust程序静态编译的两种方法总结

1. 概述 经过我的探索&#xff0c;总结了两种rust程序静态编译的方法,理论上两种方法都适用于windows、mac os和linux(mac os未验证)&#xff0c;实测方法一性能比方法二好&#xff0c;现总结如下&#xff0c;希望能够帮到你. 2.方法一 2.1 添加配置文件 在项目的同级文件夹下新…...