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

实验五 内存管理实验

实验五  内存管理实验

一、实验目的

1、了解操作系统动态分区存储管理过程和方法。

2、掌握动态分区存储管理的主要数据结构--空闲表区。

3、加深理解动态分区存储管理中内存的分配和回收。

4、掌握空闲区表中空闲区3种不同放置策略的基本思想和实现过程。

5、通过模拟程序实现动态分区存储管理。

6、了解请求分页虚拟存储管理技术的方法和特点。

7、通过模拟实现请求页式存储管理的几种基本页面置换算法。

8、掌握页面置换算法种缺页率、置换率和命中率的计算方法。

、实验内容

1、编程模拟实现动态分区管理中内存的分配和回收及空闲区表的管理。(2分)

首次适应算法(First Fit)参考程序:

#include<unistd.h>

#include<stdio.h>

#include<stdlib.h>

#define N 5

struct freearea

{

    int startaddr;  //空闲区起始地址

    int size;      //空闲区大小

    int state;     //1表示空闲,0表示占用

}freeblock[N]={{20,20,1},{80,50,1},{150,100,1},{300,30,1},{600,100,1}};

int alloc(int size)

{

    int i,tag=0,allocaddr;

    for(i=0;i<N;i++)

    {

        if(freeblock[i].state==1 && freeblock[i].size>size) //申请空间小于空闲空间

        {

           allocaddr=freeblock[i].startaddr;   //作业地址

           freeblock[i].startaddr+=size;   //新空闲区起始地址

           freeblock[i].size-=size;       //新空闲区大小

           tag=1;  //分配标记

           break;

        }

        else if(freeblock[i].state==1 && freeblock[i].size==size)//申请空间正好等于空闲空间

        {

           allocaddr=freeblock[i].startaddr;

           freeblock[i].state=0;tag=1;

           break;

        }

    }

    if(tag==0)  //表示没找到合适的空闲区,未分配内存

        allocaddr=-1;

    return allocaddr; //返回作业地址

}

void setfree(int addr,int size) //传过来的参数是要释放内存的起始地址和大小

{

    int i,tag1=0,tag2=0,n1=0,n2=0;

    for(i=0;i<N;i++)

    {

        if(freeblock[i].startaddr+freeblock[i].size==addr && freeblock[i].state==1)

        {

           tag1=1;     //有上邻标记

           n1=i;   //记录上邻数组位置(分区号)

           break;

        }

    }

    for(i=0;i<N;i++)

    {

        if(freeblock[i].startaddr==addr+size && freeblock[i].state==1) 

        {

           tag2=1;     //有下邻标记

           n2=i;   //记录下邻数组位置(分区号)

           break;

        }

    }      

    if(tag1==1 && tag2==0)  //有上邻无下邻

    {

        freeblock[n1].size+=size;

    }

    else if(tag1==1 && tag2==1) //有上邻有下邻

    {

           freeblock[n1].size+=freeblock[n2].size+size;

           freeblock[n2].state=0;//???

    }

    else if(tag1==0 && tag2==1) //无上邻有下邻

    {

        freeblock[n2].startaddr=addr;

        freeblock[n2].size+=size;

    }

    else    //无上邻无下邻(表明空间正好全部分配出去,空间的状态为0)

    {

        for(i=0;i<N;i++)

        {

           if(freeblock[i].state==0)   //通过空间状态值找到这块空间

           {

               freeblock[i].startaddr=addr;

               freeblock[i].size=size;

               freeblock[i].state=1;

               break;

           }

        }

    }

}

void adjust()

{

    int i,j;

    struct freearea temp;

    for(i=1;i<N;i++)    //依据首次适应算法将空闲区按起始地址由低到高冒泡排序

    {

        for(j=0;j<N-i;j++)

        {

           if(freeblock[j].startaddr>freeblock[j+1].startaddr)

           {

               temp=freeblock[j];

               freeblock[j]=freeblock[j+1];

               freeblock[j+1]=temp;

           }

        }

    }

    for(i=1;i<N;i++)    //把状态为0的排到后面

    {

        for(j=0;j<N-i;j++)

        {

           if(freeblock[j].state==0 && freeblock[j+1].state==1)

           {

               temp=freeblock[j];

               freeblock[j]=freeblock[j+1];

               freeblock[j+1]=temp;

           }

        }

    }

}

void print()

{

    int i;

    printf("\t|-------------------------------|\n");

    printf("\t|startaddr    size      state |\n");

    for(i=0;i<N;i++)

    printf("\t|%4d     %4d   %4d |\n",freeblock[i].startaddr,freeblock[i].size,freeblock[i].state);   

}

int main()

{

    int size,addr;

    char c1,c2,c;

    printf("At first the free memory is this:\n");//首先,空闲区是这样的

    adjust();

    print();   

    printf("Is there any job request memory?(y or n):");//有作业需要申请内存么?

    while((c1=getchar())=='y')

    {

        printf("Input request memory size:"); //输入所需内存大小

        scanf("%d",&size);

        addr=alloc(size); //调用内存分配函数,返回的是作业的起始地址

        if(addr==-1)

           printf("There is no fit memory.Please wait!!!\n");

        else

        {

           printf("Job's memory start address is:%d\n",addr);    //输出作业的起始地址

           printf("Job's size is:%d\n",size);  //输出作业大小

           printf("After allocation the free memory is this:\n");    //分配后可用内存如下:         adjust();

           print();

           printf("Job is running.\n");

        }

        getchar();

        printf("Is there any memory for free?(y or n):");//有需要释放的内存么?

        while((c2=getchar())=='y')

        {

           printf("Input free area startaddress:");

           scanf("%d",&addr);  //输入要释放内存的起始地址

           printf("Input free area size:");

           scanf("%d",&size);  //输入要释放内存的大小

           setfree(addr,size); //调用释放内存函数

           adjust();

           print();

           getchar();

           printf("Is there any memory for free?(y or n):");      

        }

        getchar();

        printf("Is there any job request memory?(y or n):");

    }

    return 0;  

}

运行结果截屏(包含分配和回收两部分):

分析该程序,列出各模块实现的功能:

  1. alloc()

根据作业的大小申请空闲内存区域,并返回作业的起始地址。

2)setfree()

释放指定起始地址和大小的内存区域,将其设置为空闲状态。

3) adjust()

根据首次适应算法对空闲区进行排序和整理。

  1. 修改上题,用最佳适应算法和最坏适应算法模拟内存空间的分配和回收。(4分)

注:只需列出程序不同部分,无需将整个程序列出。

  1. 最佳适应算法

int best_fit_alloc(int size) {

    int i, allocaddr = -1, min_size = INT_MAX;

    for (i = 0; i < N; i++) {

        if (freeblock[i].state == 1 && freeblock[i].size >= size && freeblock[i].size < min_size) {

            allocaddr = freeblock[i].startaddr;

            min_size = freeblock[i].size;

        }

    }

    if (allocaddr != -1) {

        for (i = 0; i < N; i++) {

            if (freeblock[i].startaddr == allocaddr) {

                if (freeblock[i].size > size) {

                    freeblock[i].startaddr += size;

                    freeblock[i].size -= size;

                } else {

                    freeblock[i].state = 0;

                }

                break;

            }

        }

    }

   

    return allocaddr;

}

  1. 最坏适应算法

int worst_fit_alloc(int size) {

    int i, allocaddr = -1, max_size = -1;

    for (i = 0; i < N; i++) {

        if (freeblock[i].state == 1 && freeblock[i].size >= size && freeblock[i].size > max_size) {

            allocaddr = freeblock[i].startaddr;

            max_size = freeblock[i].size;

        }

    }

    if (allocaddr != -1) {

        for (i = 0; i < N; i++) {

            if (freeblock[i].startaddr == allocaddr) {

                if (freeblock[i].size > size) {

                    freeblock[i].startaddr += size;

                    freeblock[i].size -= size;

                } else {

                    freeblock[i].state = 0;

                }

                break;

            }

        }

    }

   

    return allocaddr;

}

  1. 编写程序实现先进先出页面置换算法,并计算缺页次数,缺页率,置换次数和命中率。(2分)

参考程序:

#include <stdio.h>

//初始化内存队列

void initializeList(int list[],int number){

    int i;

    for (i = 0; i < number; i ++) {

        list[i] = -1;

    }

}

//展示要访问页面号数组

void showList(int list[], int number){

    int i;

    for (i = 0; i < number; i ++) {

        printf("%2d",list[i]);

    }

    printf("\n");

}

//展示当前内存状态

void showMemoryList(int list[],int phyBlockNum){

    int i;

    for (i = 0; i < phyBlockNum; i ++) {

        if (list[i] == -1) {

            break;

        }

        printf(" |%d|",list[i]);

    }

    printf("\n");

}

//计算各项指标

void informationCount(int missingCount,int replaceCount,int pageNum){

    printf("缺页次数:%d   缺页率:%d/%d\n",missingCount,missingCount,pageNum);

    double result = (double)(pageNum - missingCount)/(double)pageNum;

    printf("置换次数:%d  命中率:%.2f\n",replaceCount,result);

}

//先进先出置换算法

void replacePageByFIFO(int memoryList[],int phyNum,int strList[],int pageNum){

    //置换次数

    int replaceCount = 0;

    //缺页次数

    int missingCount = 0;

    //记录当前最早进入内存的下标

    int pointer = 0;

  

//记录当前页面的访问情况: 0 未访问

int i,j,isVisited = 0;

    for (i = 0; i < pageNum; i ++) {

        isVisited = 0;

        //判断是否需要置换->内存已满且需要访问的页面不在内存中

        for (j = 0; j < phyNum; j ++) {

            if (memoryList[j] == strList[i]) {

                //该页面已经存在内存中

                //修改访问情况

                isVisited = 1;

                //展示

                printf("%d\n",strList[i]);

                break;

            }

            if (memoryList[j] == -1) {

                //页面不在内存中且内存未满->直接存入

                memoryList[j] = strList[i];

                //修改访问情况

                isVisited = 1;

                missingCount ++;

                //展示

                printf("%d\n",strList[i]);

                showMemoryList(memoryList, phyNum);

                break;

            }

        }

        if (!isVisited) {

            //当前页面还未被访问过->需要进行页面置换

            //直接把这个页面存到所记录的下标中

            memoryList[pointer] = strList[i];

            //下标指向下一个

            pointer ++;

            //如果到了最后一个,将下标归零

            if (pointer > phyNum-1) {

                pointer = 0;

            }          

            missingCount ++;

            replaceCount ++;

            //展示

            printf("%d\n",strList[i]);

            showMemoryList(memoryList, phyNum);

        }

    }

    informationCount(missingCount, replaceCount, pageNum);//计算各项指标

}

int main(int argc, const char * argv[]) { 

//物理块的数量

    int phyBlockNum;

    printf("请输入物理块数量:\n");

scanf("%d",&phyBlockNum);

    //生成内存队列数组

int memoryList[phyBlockNum];

    //初始化内存状态

    initializeList(memoryList, phyBlockNum);

//showMemoryList(memoryList,phyBlockNum);

    //页面数量

    int pageNum;

    printf("请输入要访问的页面总数:\n");

scanf("%d",&pageNum);

    //保存页面号数组

    int pageNumStrList[pageNum];

    int i;

//将要访问的页面号存入数组中

    printf("请输入要访问的页面号:\n");

    for (i = 0; i < pageNum; i ++) {

        scanf("%d",&pageNumStrList[i]);

}

    //显示要访问页面号数组中内容

showList(pageNumStrList, pageNum);

    int chose;

    while (1) {

        printf("请选择所需的置换算法:\n");

        printf("1.FIFO 2.退出\n");

        scanf("%d",&chose);

       

        switch (chose) {

            case 1:

//显示要访问页面号数组中内容

                showList(pageNumStrList, pageNum);

//调用先进先出置换算法

                replacePageByFIFO(memoryList, phyBlockNum, pageNumStrList, pageNum);

                //重新初始化内存

                initializeList(memoryList , phyBlockNum);

                break;

            default:

                return 0;

                break;

        }

    }   

    return 0;

}

编译及执行过程以及结果截屏:

分析程序功能:

1.用户输入物理块数量和要访问的页面总数。

2.用户输入要访问的页面号,将其存入一个数组中。

3.用户选择要使用的置换算法,目前只支持FIFO算法。

4.程序调用replacePageByFIFO函数来执行FIFO算法: a. 该函数通过遍历页面号数组,判断页面是否在内存中,如果在则不进行操作,如果不在则进行页面置换。 b. 如果内存未满,直接将页面存入内存;如果内存已满,将最早进入内存的页面置换出去,并将新页面存入内存。 c. 统计缺页次数和置换次数,并展示当前内存状态。

5.调用informationCount函数计算并展示各项指标,包括缺页次数、缺页率、置换次数和命中率。

6.重新初始化内存,回到步骤3,直到用户选择退出程序为止。

  1. 编程实现其它页面置换算法(如最近最久未使用算法或最佳置换算法等),计算缺页次数,缺页率,置换次数和命中率。(1分)

#include <stdio.h>

#define MAX_PAGES 100

#define MAX_FRAMES 10

// 初始化页面访问序列

void initializePages(int pages[], int numPages) {

    printf("请输入页面访问序列(以-1结束):\n");

    int i = 0;

    do {

        scanf("%d", &pages[i]);

        i++;

    } while (pages[i-1] != -1 && i < numPages);

}

// LRU算法

int lru(int pages[], int numPages, int numFrames) {

    int frames[MAX_FRAMES] = {-1}; // 帧表

    int lruCount[MAX_FRAMES] = {0}; // 记录每个帧最后一次使用的时间

    int numFaults = 0; // 缺页次数

    int numReplacements = 0; // 置换次数

    int numHits = 0; // 命中次数

    int time = 0; // 记录时间

   

    for (int i = 0; i < numPages; i++) {

        int page = pages[i];

        int j;

        for (j = 0; j < numFrames; j++) {

            if (frames[j] == page) {

                numHits++;

                lruCount[j] = time;

                break;

            }

        }

        if (j == numFrames) {

            int lruIndex = 0;

            for (int k = 1; k < numFrames; k++) {

                if (lruCount[k] < lruCount[lruIndex]) {

                    lruIndex = k;

                }

            }

            frames[lruIndex] = page;

            lruCount[lruIndex] = time;

            numFaults++;

            numReplacements++;

        }

        time++;

    }

   

    printf("\nLRU算法结果:\n");

    printf("缺页次数:%d\n", numFaults);

    printf("缺页率:%f\n", (float)numFaults/numPages);

    printf("置换次数:%d\n", numReplacements);

    printf("命中率:%f\n\n", (float)numHits/numPages);

   

    return numFaults;

}

// 最佳置换算法

int optimal(int pages[], int numPages, int numFrames) {

    int frames[MAX_FRAMES] = {-1}; // 帧表

    int numFaults = 0; // 缺页次数

    int numReplacements = 0; // 置换次数

    int numHits = 0; // 命中次数

   

    for (int i = 0; i < numPages; i++) {

        int page = pages[i];

        int j;

        for (j = 0; j < numFrames; j++) {

            if (frames[j] == page) {

                numHits++;

                break;

            }

        }

        if (j == numFrames) {

            int replaceIndex = -1;

            int found = 0;

            for (int k = 0; k < numFrames; k++) {

                int m;

                for (m = i+1; m < numPages; m++) {

                    if (frames[k] == pages[m]) {

                        found = 1;

                        if (m > replaceIndex) {

                            replaceIndex = m;

                        }

                        break;

                    }

                }

                if (!found) {

                    replaceIndex = k;

                    break;

                }

            }

            frames[replaceIndex] = page;

            numFaults++;

            numReplacements++;

        }

    }

   

    printf("最佳置换算法结果:\n");

    printf("缺页次数:%d\n", numFaults);

    printf("缺页率:%f\n", (float)numFaults/numPages);

    printf("置换次数:%d\n", numReplacements);

    printf("命中率:%f\n\n", (float)numHits/numPages);

   

    return numFaults;

}

int main() {

    int pages[MAX_PAGES];

    int numPages;

    int numFrames;

   

    printf("请输入页面数:");

    scanf("%d", &numPages);

    printf("请输入帧数:");

    scanf("%d", &numFrames);

   

    initializePages(pages, numPages);

   

    lru(pages, numPages, numFrames);

    optimal(pages, numPages, numFrames);

   

    return 0;

}

  1. 编程用动态分区链形式模拟动态分区管理中内存的分配和回收,采用3种算法(首次适应算法,最佳适应算法,最坏适应算法)实现。(附加题)

#include <stdio.h>

#include <stdlib.h>

#define MAX_SIZE 100

typedef struct Node {

    int start;

    int end;

    int size;

    int status; // 0表示未分配,1表示已分配

    struct Node* next;

} Node;

Node* head = NULL;

// 初始化内存

void initMemory() {

    head = (Node*)malloc(sizeof(Node));

    head->start = 0;

    head->end = MAX_SIZE;

    head->size = MAX_SIZE;

    head->status = 0;

    head->next = NULL;

}

// 打印内存分配情况

void printMemory() {

    Node* current = head;

    while (current != NULL) {

        printf("[%d-%d] Size: %d ", current->start, current->end, current->size);

        if (current->status == 0) {

            printf("Status: Free\n");

        } else {

            printf("Status: Allocated\n");

        }

        current = current->next;

    }

    printf("\n");

}

// 首次适应算法分配内存

void* allocateFirstFit(int size) {

    Node* current = head;

    while (current != NULL) {

        if (current->status == 0 && current->size >= size) {

            int remainingSize = current->size - size;

            if (remainingSize > 0) {

                Node* newNode = (Node*)malloc(sizeof(Node));

                newNode->start = current->start;

                newNode->end = current->start + size;

                newNode->size = size;

                newNode->status = 1;

                newNode->next = current->next;

                current->start = newNode->end;

                current->size = remainingSize;

                current->next = newNode;

            } else {

                current->status = 1;

            }

            return (void*)current->start;

        }

        current = current->next;

    }

    return NULL;

}

// 最佳适应算法分配内存

void* allocateBestFit(int size) {

    Node* current = head;

    Node* bestFitBlock = NULL;

    int bestFitSize = MAX_SIZE + 1;

    while (current != NULL) {

        if (current->status == 0 && current->size >= size && current->size < bestFitSize) {

            bestFitBlock = current;

            bestFitSize = current->size;

        }

        current = current->next;

    }

    if (bestFitBlock != NULL) {

        int remainingSize = bestFitBlock->size - size;

        if (remainingSize > 0) {

            Node* newNode = (Node*)malloc(sizeof(Node));

            newNode->start = bestFitBlock->start;

            newNode->end = bestFitBlock->start + size;

            newNode->size = size;

            newNode->status = 1;

            newNode->next = bestFitBlock->next;

            bestFitBlock->start = newNode->end;

            bestFitBlock->size = remainingSize;

            bestFitBlock->next = newNode;

        } else {

            bestFitBlock->status = 1;

        }

        return (void*)bestFitBlock->start;

    }

    return NULL;

}

// 最坏适应算法分配内存

void* allocateWorstFit(int size) {

    Node* current = head;

    Node* worstFitBlock = NULL;

    int worstFitSize = -1;

    while (current != NULL) {

        if (current->status == 0 && current->size >= size && current->size > worstFitSize) {

            worstFitBlock = current;

            worstFitSize = current->size;

        }

        current = current->next;

    }

    if (worstFitBlock != NULL) {

        int remainingSize = worstFitBlock->size - size;

        if (remainingSize > 0) {

            Node* newNode = (Node*)malloc(sizeof(Node));

            newNode->start = worstFitBlock->start;

            newNode->end = worstFitBlock->start + size;

            newNode->size = size;

            newNode->status = 1;

            newNode->next = worstFitBlock->next;

            worstFitBlock->start = newNode->end;

            worstFitBlock->size = remainingSize;

            worstFitBlock->next = newNode;

        } else {

            worstFitBlock->status = 1;

        }

        return (void*)worstFitBlock->start;

    }

    return NULL;

}

// 回收内存

void deallocate(void* addr) {

    Node* current = head;

    Node* prev = NULL;

    while (current != NULL) {

        if (current->start == (int)addr) {

            current->status = 0;

            // 合并相邻的空闲块

            if (prev != NULL && prev->status == 0) {

                prev->end = current->end;

                prev->size += current->size;

                prev->next = current->next;

                free(current);

                current = prev;

            }

            if (current->next != NULL && current->next->status == 0) {

                current->end = current->next->end;

                current->size += current->next->size;

                Node* temp = current->next->next;

                free(current->next);

                current->next = temp;

            }

            return;

        }

        prev = current;

        current = current->next;

    }

}

int main() {

    initMemory();

    printMemory();

    void* addr1 = allocateFirstFit(20);

    printf("Allocated block: [0-20]\n");

    printMemory();

    void* addr2 = allocateBestFit(30);

    printf("Allocated block: [20-50]\n");

    printMemory();

    void* addr3 = allocateWorstFit(40);

    printf("Allocated block: [50-90]\n");

    printMemory();

    deallocate(addr2);

    printf("Deallocated block: [20-50]\n");

    printMemory();

    deallocate(addr1);

    printf("Deallocated block: [0-20]\n");

    printMemory();

    void* addr4 = allocateBestFit(70);

    printf("Allocated block: [0-70]\n");

    printMemory();

    return 0;

}

三、实验总结和体会(1分)

通过实际编写程序实现内存分配与回收的算法,我更加理解了这些算法的原理和实现方式。其次,通过对比不同算法的性能,我能够更加准确地选择适合当前需求的算法。最后,我还学到了一些实际应用中的内存管理技巧和策略,为日后的工作打下了基础。

在实验过程中,我发现自己对于某些算法和概念的理解还不够深入,需要进一步学习和加强。此外,我在实验中遇到了一些问题,如编写不完善的算法导致程序出错等,这些问题提醒我需要加强对代码质量和细节的把控。

相关文章:

实验五 内存管理实验

实验五 内存管理实验 一、实验目的 1、了解操作系统动态分区存储管理过程和方法。 2、掌握动态分区存储管理的主要数据结构--空闲表区。 3、加深理解动态分区存储管理中内存的分配和回收。 4、掌握空闲区表中空闲区3种不同放置策略的基本思想和实现过程。 5、通过模拟程…...

初识 Firebase 与 FPM

Firebase 是什么 ? Firebase 是 Google 旗下面向 iOS、Android、Web 与多端框架&#xff08;Flutter、Unity 等&#xff09;的应用开发平台&#xff0c;提供从「构建 → 发布与运维 → 增长」全生命周期的一站式后端即服务&#xff08;BaaS&#xff09;。它把实时数据库、托管…...

探索C++中的数据结构:栈(Stack)的奥秘

引言 栈是计算机科学中最基础且重要的数据结构之一&#xff0c;它像一摞盘子一样遵循"后进先出"&#xff08;LIFO&#xff09;的原则。无论是函数调用、表达式求值&#xff0c;还是浏览器前进后退功能&#xff0c;栈都扮演着关键角色。本文将深入解析栈的C实现及其应…...

vue3 nprogress 使用

nprogress 介绍与作用 1.nprogress 是一个轻量级的进度条组件&#xff0c;主要用于在页面加载或路由切换时显示一个进度条&#xff0c;提升用户体验。它的原理是通过在页面顶部创建一个 div&#xff0c;并使用 fixed 定位来实现进度条的效果 2.在 Vite Vue 3 项目中&#xf…...

MCP(Model Context Protocol 模型上下文协议)科普

MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09;是由人工智能公司 Anthropic 于 2024年11月 推出的开放标准协议&#xff0c;旨在为大型语言模型&#xff08;LLM&#xff09;与外部数据源、工具及服务提供标准化连接&#xff0c;从而提升AI在实际…...

韩媒专访CertiK创始人顾荣辉:黑客攻击激增300%,安全优先的破局之路

4月17日&#xff0c;韩国知名科技媒体《韩国IT时报》(Korea IT Times)发布了对CertiK联合创始人兼CEO顾荣辉教授的专访。双方围绕CertiK一季度《HACK3D》安全报告&#xff0c;就黑客攻击手法的迭代和安全防御技术的创新路径等&#xff0c;展开深度对话。 顾荣辉认为&#xff0…...

华为openEuler操作系统全解析:起源、特性与生态对比

华为openEuler操作系统全解析&#xff1a;起源、特性与生态对比 一、起源与发展历程 openEuler&#xff08;欧拉操作系统&#xff09;是华为于2019年开源的Linux发行版&#xff0c;其前身为华为内部研发的服务器操作系统EulerOS。EulerOS自2010年起逐步发展&#xff0c;支持华…...

从零实现Git安装、使用

一、git安装 Git官方下载 1.下载exe程序 2.双击安装&#xff0c;一直点击next&#xff0c;默认安装 安装完成后&#xff0c;在任意文件夹右键&#xff0c;出现下图所示&#xff0c;即为安装成功。 3.【Git Bash Here】调出命令窗口&#xff0c;设置用户名和 email 地址。 gi…...

leetcode刷题日记——单词规律

[ 题目描述 ]&#xff1a; [ 思路 ]&#xff1a; 题目要求判断字符串 s 中的单词是否按照 pattern 这种模式排列具体思路和 205. 同构字符串基本一致&#xff0c;可以通过 hash 存储来实现思路二&#xff0c;通过字符串反推 pattern&#xff0c;如果一致&#xff0c;则遵循相…...

Ubuntu 修改语言报错Failed to download repository information

1.进入文件(ps:vim可能出现无法修改sources.list文件的问题&#xff09; sudo gedit /etc/apt/sources.list2.修改(我是直接增添以下内容在其原始源前面&#xff0c;没有删原始内容)文件并保存&#xff0c;这里会替换原文件 deb http://mirrors.aliyun.com/ubuntu/ focal mai…...

烹饪与餐饮管理实训室数字课程开发方案

烹饪与餐饮管理专业需要具有餐饮产品设计、研发的能力&#xff1b; 具有饮食美学、科学配餐与高端宴席设计的能力&#xff1b; 具有餐饮企业、中央厨房运营管理的能力&#xff1b; 具有餐饮信息化系统应用、数字化运营的能力&#xff0c;这些能力的培养&#xff0c;需要烹饪与餐…...

关于模拟噪声分析的11个误区

目录 1. 降低电路中的电阻值总是能改善噪声性能 2. 所有噪声源的噪声频谱密度可以相加&#xff0c;带宽可以在最后计算时加以考虑 3. 手工计算时必须包括每一个噪声源 4. 应挑选噪声为ADC 1/10的ADC驱动器 5. 直流耦合电路中必须始终考虑1/f噪声 6. 因为1/f噪声随着频率降…...

基于 S2SH 架构的企业车辆管理系统:设计、实现与应用

在企业运营中&#xff0c;车辆管理是一项重要工作。随着企业规模的扩大&#xff0c;车辆数量增多&#xff0c;传统管理方式效率低下&#xff0c;难以满足企业需求。本文介绍的基于 S2SH 的企业车辆管理系统&#xff0c;借助现代化计算机技术&#xff0c;实现车辆、驾驶员和出车…...

51单片机实验七:EEPROM AT24C02 与单片机的通信实例

目录 一、实验环境与实验器材 二、实验内容及实验步骤 三、proteus复位电路 1.改电阻的阻值&#xff08;方法一&#xff09; 2.改电阻的属性&#xff08;方法2&#xff09; 一、实验环境与实验器材 环境&#xff1a;Keli&#xff0c;STC-ISP烧写软件,Proteus. …...

【TeamFlow】 1 TeamFlow 去中心化生产协同系统架构

总体架构设计 采用四层混合架构&#xff0c;结合分层设计与去中心化网络&#xff1a; #mermaid-svg-qBgw9wMd8Gi0gOci {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-qBgw9wMd8Gi0gOci .error-icon{fill:#552222;}…...

第 8 期:条件生成 DDPM:让模型“听话”地画图!

本期关键词&#xff1a;Conditional DDPM、Class Embedding、Label Control、CIFAR-10 条件生成 什么是条件生成&#xff08;Conditional Generation&#xff09;&#xff1f; 在标准的 DDPM 中&#xff0c;我们只是“随机生成”图像。 如果我想让模型生成「小狗」怎么办&…...

树莓派超全系列教程文档--(32)config.txt常用音频配置

config.txt常用音频配置 板载模拟音频&#xff08;3.5mm耳机插孔&#xff09;audio_pwm_modedisable_audio_ditherenable_audio_ditherpwm_sample_bits HDMI音频 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 板载模拟音频&#xff08;3.5mm耳机…...

Perf学习

重要的能解决的问题是这些&#xff1a; perf_events is an event-oriented observability tool, which can help you solve advanced performance and troubleshooting functions. Questions that can be answered include: Why is the kernel on-CPU so much? What code-pa…...

量子神经网络编译器开发指南:从理论突破到产业落地全景解析

本文深度剖析IBM Qiskit 5.0量子经典混合编译器的技术架构&#xff0c;详解如何基于含噪量子处理器实现MNIST手写数字分类任务&#xff08;准确率达89%&#xff09;。结合本源量子云、百度量子等国内平台免费配额政策&#xff0c;系统性阐述量子神经网络开发的技术路线与资源获…...

守护者进程小练习

守护者进程含义 定义&#xff1a;守护进程&#xff08;Daemon&#xff09;是运行在后台的特殊进程&#xff0c;独立于控制终端&#xff0c;周期性执行任务或等待事件触发。它通常以 root 权限运行&#xff0c;名称常以 d 结尾&#xff08;如 sshd, crond&#xff09;。 特性&a…...

研究生面试常见问题

研究生面试是考研复试的重要环节&#xff0c;面试表现直接关系到录取结果。以下从面试流程、常见问题分类及回答技巧等方面为您整理了相关内容&#xff0c;帮助您更好地准备面试。 一、研究生面试的基本流程 自我介绍&#xff1a;通常需要准备1分钟左右的中文或英文自我介绍&a…...

极狐GitLab 登录限制如何设置?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 登录限制 (BASIC SELF) 您可以使用登录限制自定义 Web 界面以及基于 HTTP(S) 的 Git 的身份验证限制。 设置 要访问登录限…...

AI驱动商业变革:零售行业的智能化跃迁

引言&#xff1a;AI技术迈入黄金时代 2024年成为生成式AI&#xff08;Gen AI&#xff09;全面落地的关键年。据麦肯锡《技术趋势展望》报告&#xff0c;生成式AI相关投资同比增长​7倍​​&#xff0c;其经济价值预计达​​2.6-4.4万亿美元​​[1]。在零售领域&#xff0c;该技…...

初始图像学(6)

Camera类 我们之前学了很多的图形学知识和相关的程序&#xff0c;现在我们停下脚步&#xff0c;来好好整理一下我们学习的内容&#xff0c;我们将之前的视口代码和渲染代码合并到一个新的单类camera.h&#xff0c;这个类主要负责两项任务&#xff1a; 构建并发射光线到世界中 …...

【React】通过 fetch 发起请求,设置 proxy 处理跨域

fetch 基本使用跨域处理 fetch 基本使用 在node使用原生ajax发请求&#xff1a;XMLHttpRequest()1.获取xhr对象 2.注册回调函数 3.设置参数&#xff0c;请求头 4.发起连接原生ajax没有带异步处理 promise&#xff1b;原生ajax封装一下&#xff0c;以便重复调用jQuery&#…...

好数对的数目

题目描述 给你一个整数数组 nums。 如果一组数字 (i, j) 满足 nums[i] nums[j] 且 i < j&#xff0c;就可以认为这是一组 好数对。 返回 好数对 的数目。 示例 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3,1,1,3] 输出&#xff1a;4 解释&#xff1a; 有 4 组好…...

Animated Raindrop Ripples In HLSL

这节课是利用材质做雨滴i效果 首先是创建一个圆环&#xff0c;实际上他就是为了创建一个圆&#xff0c;但是是空心的&#xff0c;可以看之前我的做法&#xff0c;这里以他的为准 创建圆环 就是当uv的点在max_radius和min_radius之间的时候绘制。 他这里写了ringThickness&a…...

Linux学习——守护进程编程

一、守护进程含义及实现过程 1、含义 守护进程&#xff08;Daemon Process&#xff09; 是操作系统中一种在后台长期运行的特殊进程&#xff0c;通常不与用户直接交互。它独立于控制终端&#xff0c;用于执行周期性任务或系统服务&#xff08;如日志管理、网络服务等&#xff…...

【C++】 —— 笔试刷题day_19

一、小易的升级之路 题目解析 小易现在要打游戏&#xff0c;现在游戏角色的初始能力值为a&#xff0c;我们会遇到n个怪&#xff0c;这些怪物的防御值为b1、b2、b3...&#xff0c;如果我们的能力值要高于或者等于怪物的防御值&#xff0c;那我们的能力值就会加bi&#xff1b;如…...

gitee提交大文件夹

# 安装 Git LFS&#xff08;如果未安装&#xff09; git lfs install# 跟踪整个大文件夹&#xff08;或特定大文件类型&#xff09; git lfs track "big_folder/**" # 替换为你的文件夹名# 提交并推送 git add .gitattributes big_folder/ git commit -m "add …...

纯CSS实现自动滚动到底部

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>自动滚动到底部</title><style>*…...

WInform当今技术特性分析

Windows Forms (WinForms) 技术特性分析 引言 Windows Forms (WinForms) 作为微软最早推出的基于.NET的图形用户界面开发框架&#xff0c;已经存在了20多年。在如今充满了各种现代UI框架的软件开发生态系统中&#xff0c;WinForms仍然保持着其独特的地位。本文将深入分析WinF…...

6.5 GitHub监控系统实战:双通道采集+动态调度打造高效运维体系

GitHub Sentinel Agent 定期更新功能设计与实现 关键词:GitHub API 集成、定时任务调度、Python 爬虫开发、SMTP 邮件通知、系统稳定性保障 1. GitHub 项目数据获取功能 1.1 双通道数据采集架构设计 #mermaid-svg-ZHJIMXcMAyDHVhmV {font-family:"trebuchet ms",v…...

自动驾驶安全模型研究

自动驾驶安全模型研究 自动驾驶安全模型研究 自动驾驶安全模型研究1.自动驾驶安全模型概述2. 自动驾驶安全模型应用3. 自动驾驶安全模型介绍3.1 Last Point to Steer3.2 Safety Zone3.3 RSS (Responsibility-Sensitive Safety)3.4 SFF (Safety Force Field)3.5 FSM (Fuzzy Safe…...

4090租用,各云GPU平台价格对比清单及建议

根据各平台的价格和型号配置&#xff0c;以下是通过DeepSeek-R1进行分析后&#xff0c;给出的建议。 一、按显存需求推荐 1.24G显存需求&#xff08;适合常规AI训练/推理、中小模型&#xff09; 性价比首选&#xff1a;智星云&#xff08;1.35元/小时&#xff09; &#xff0…...

Linux:简单指令(二)

文章目录 man ~~echocatcp指令which ~~mvless时间相关的指令find 要么对内容要么对属性操作 决定路径开始定位文件&#xff0c;也可以相对路径 家目录/ man ~~ 1查询具体命令 我们可以man man 可以看man 的描述 我们可以man 数字 ~~ 可以从上到下查询 2查询仿命令 3查询具体接口…...

代码随想录算法训练营day7(字符串)

华子目录 反转字符串中的单词思路 右旋字符串思路 反转字符串中的单词 https://leetcode.cn/problems/reverse-words-in-a-string/description/ 思路 先将字符串s按照空格切分为列表s_list&#xff08;使用s.split()&#xff09;再进行反转操作再将列表拼接为字符串&#xff…...

Android studio—socketIO库的emit与return的使用

文章目录 一、Socket.IO库简单使用说明1. 后端 Flask Flask-SocketIO2. Android 客户端集成 Socket.IO3. 布局文件注意事项 二、接受服务器消息的二种方法1. 客户端接收通过 emit 发送的消息功能使用场景后端代码&#xff08;Flask-SocketIO&#xff09;客户端代码&#xff08…...

【Drools+springboot3规则匹配】

文章目录 一、 业务场景概述二、整体技术架构三、Drools概述1. Drools 简介2. Drools Rete 算法与flink-cep的区别?2.1 Rete 算法概述2.2 Flink CEP 概述四、代码实现4.1 导入依赖4.2 从kafka消费数据4.3 核心类,触发匹配操作并将匹配数据写入mysql4.4 Drools 管理4.5 相关的…...

MAC-如果是分页查询,怎么分批次in;基于多线程的分页查询工具类

如果是分页查询,in怎么分批 在处理分页查询时,如果 IN 子句中的参数数量过大(例如超过数据库限制,如 MySQL 的 max_allowed_packet 或性能瓶颈),可以通过 ​​分批查询​​ 和 ​​结果合并​​ 的方式解决。以下是具体实现步骤: ​​1. 核心思路​​ 将大的 IN 列表拆…...

【MySQL】Ubuntu下C++连接MySQL

C连接MySQL ubuntu下载MySQL1.构建mysql对象&#xff0c;获得mysql访问句柄2.mysql的连接3.向mysqld下达命令(增删改)3.C_C查询细节处理3.1 下达查询命令3.2 转储查询结果3.3显示查询结果 4.编译链接 ubuntu下载MySQL sudo apt install libmysqlclient-dev下载完毕&#xff0c…...

二月公开赛 宝塔搭建Web-ssrfme环境以及漏洞复现

一.环境搭建 1.1宝塔安装docker 1.2将Web-ssrfme压缩文件放入Ubuntu并解压 rooteden-virtual-machine:/# mkdir Web-ssrfmerooteden-virtual-machine:/Web-ssrfme# ll total 2956 drwxr-xr-x 2 root root 4096 4月 18 02:43 ./ drwxr-xr-x 24 root root 4096 4月 18…...

2021 CCF CSP-S2.廊桥分配

目录 题目算法标签: 模拟, 贪心, 堆思路代码 题目 4090. 廊桥分配 算法标签: 模拟, 贪心, 堆 思路 可以将每个飞机的起始时间和离开时间看作一个线段, 每个廊桥在同一时间只能服务一架飞机, 因为先到先得因此是按照起始时间进行排序 每个廊桥只关心最后一架飞机离开的时刻…...

博客标题栏添加一个 About Me

文章目录 ✅ 目标✍️ 第一步&#xff1a;创建 About 页面&#x1f9ed; 第二步&#xff1a;在导航栏添加菜单项&#x1f504; 第三步&#xff1a;重新启动本地服务&#x1fa84; 可选美化&#xff1a;自定义样式&#x1f4a1; 小贴士&#x1f389; 示例✅ 文件路径:✅ 页面代码…...

transient关键字深度解析

Java transient 关键字深度解析 1. 核心概念 (1) 基本定义 作用:标记字段不参与序列化 适用场景: 敏感数据(如密码、密钥) 临时计算字段 依赖运行时环境的字段(如Thread对象) (2) 语法示例 java public class User implements Serializable {private String username…...

解决 pip install tts 报错问题-—SadTalker的AI数字人视频—未来之窗超算中心

pip install -r requirements.txt pip install TTS0.11.1 指定版本 pip install TTS0.11.1...

Java 数据类型全解析:基础、引用与包装类全面梳理

Java 中的数据类型分为两大类&#xff1a; &#x1f9e9; 一、基本数据类型&#xff08;Primitive Types&#xff09; 共 8 种&#xff0c;分为 数值类型、字符类型、布尔类型&#xff1a; 类型占用内存默认值说明byte1 字节0整数类型&#xff0c;范围 -128 ~ 127short2 字节…...

Linux计划任务详解:原理、优缺点及应用

Linux计划任务详解&#xff1a;原理、优缺点及应用 文章目录 Linux计划任务详解&#xff1a;原理、优缺点及应用计划任务的基本原理Cron工作原理At工作原理 计划任务的优缺点优点缺点 crontab 命令详解&#xff1a;用法与选项全指南基本语法常用选项详解1. 编辑 cron 任务 (-e)…...

MODBUS TCP 转 CANOpen

一、产品概述 1.1 产品用途 SG-TCP-COE-210 网关可以实现将 CANOpen 接口设备连接到 MODBUS TCP 网络中。用户不需要了解具体的 CANOpen 和 Modbus TCP 协议即可实现将 CANOpen 设备挂载到 MODBUS TCP 接口的 PLC 上&#xff0c;并和 CANOpen 设备进行 数…...

00.IDEA 插件推荐清单(2025)

IDEA 插件推荐清单 精选高效开发必备插件&#xff0c;提升 Java 开发体验与效率。 参考来源&#xff1a;十六款好用的 IDEA 插件&#xff0c;强烈推荐&#xff01;&#xff01;&#xff01;不容错过 代码开发助手类 插件名称功能简介推荐指数CodeGeeX智能代码补全、代码生成、…...