实验五 内存管理实验

实验五  内存管理实验

一、实验目的

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分)

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

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

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

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

相关文章

【MySQL】MySQL表的增删改查(CRUD) —— 上篇

目录 MySQL表的增删改查&#xff08;CRUD&#xff09; 1. 新增&#xff08;Create&#xff09;/插入数据 1.1 单行数据 全列插入 insert into 表名 values(值, 值......); 1.2 单行数据 指定列插入 1.3 多行数据 指定列插入 1.4 关于时间日期&#xff08;datetime&am…

【MATLAB代码例程】AOA与TOA结合的高精度平面地位,适用于四个基站的情况,附完整的代码

本代码实现了一种基于到达角(AOA) 和到达时间(TOA) 的混合定位算法,适用于二维平面内移动或静止目标的定位。通过4个基站的协同测量,结合最小二乘法和几何解算,能够有效估计目标位置,并支持噪声模拟、误差分析和可视化输出。适用于室内定位、无人机导航、工业监测等场景…

ModbusTCP 转 Profinet 主站网关

一、 功能概述 1.1 设备简介 本产品是 ModbusTCP 和 Profinet(M) 网关&#xff08;以下简称网关&#xff09;&#xff0c;使用数据映射 方式工作。 本产品在 ModbusTCP 侧作为 ModbusTCP 从站&#xff0c;接 PLC 、上位机、 wincc 屏 等&#xff1b;在 Profin…

《AI大模型应知应会100篇》第25篇:Few-shot与Zero-shot使用方法对比

第25篇&#xff1a;Few-shot与Zero-shot使用方法对比 摘要 在大语言模型的应用中&#xff0c;**Few-shot&#xff08;少样本&#xff09;和Zero-shot&#xff08;零样本&#xff09;**是两种核心的提示策略。它们各自适用于不同的场景&#xff0c;能够帮助用户在不进行额外训练…

深入理解C++中string的深浅拷贝

目录 一、引言 二、浅拷贝与深拷贝的基本概念 2.1 浅拷贝 2.2 深拷贝 在C++ 中, string 类的深浅拷贝有着重要的区别。 浅拷贝 深拷贝 string 类中的其他构造函数及操作 resize 构造 = 构造(赋值构造) + 构造(拼接构造) cin 和 cin.get 的区别 三、C++中string类的…

在Qt中验证LDAP账户(Windows平台)

一、前言 原本以为在Qt&#xff08;Windows平台&#xff09;中验证 LDAP 账户很简单&#xff1a;集成Open LDAP的开发库即可。结果临了才发现&#xff0c;Open LDAP压根儿不支持Windows平台。沿着重用的原则&#xff0c;考虑迁移Open LDAP的源代码&#xff0c;却发现工作量不小…

《软件设计师》复习笔记(11.4)——处理流程设计、系统设计、人机界面设计

目录 一、业务流程建模 二、流程设计工具 三、业务流程重组&#xff08;BPR&#xff09; 四、业务流程管理&#xff08;BPM&#xff09; 真题示例&#xff1a; 五、系统设计 1. 主要目的 2. 设计方法 3. 主要内容 4. 设计原则 真题示例&#xff1a; 六、人机界面设…

UniRig ,清华联合 VAST 开源的通用自动骨骼绑定框架

UniRig是清华大学计算机系与VAST联合开发的前沿自动骨骼绑定框架&#xff0c;专为处理复杂且多样化的3D模型而设计。基于强大的自回归模型和骨骼点交叉注意力机制&#xff0c;UniRig能够生成高质量的骨骼结构和精确的蒙皮权重&#xff0c;大幅提升动画制作的效率和质量。 UniR…

LeetCode 443 压缩字符串

字符数组压缩算法详解&#xff1a;实现与分析 一、引言 在处理字符数组时&#xff0c;我们常常遇到需要对连续重复字符进行压缩的场景。这不仅可以节省存储空间&#xff0c;还能提升数据传输效率。本文将深入解析一个经典的字符数组压缩算法&#xff0c;通过详细的实现步骤和…

alertManager部署安装、告警规则配置详解及告警消息推送

​ java接受告警请求RestController RequestMapping("/alert") Slf4j public class TestApi {private static final DateTimeFormatter FORMATTER DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");RequestMappingpublic void sendTemplate(HttpServl…

数据库勒索病毒威胁升级:企业数据安全防线如何用安当RDM组件重构

摘要&#xff1a;2025年Q1全球数据库勒索攻击量同比激增101.8%&#xff0c;Cl0p、Akira等团伙通过边缘设备漏洞渗透企业核心系统&#xff0c;制造业、金融业等关键领域面临数据加密与业务停摆双重危机。本文深度解析勒索病毒对数据库的五大毁灭性影响&#xff0c;结合安当RDM防…

thanos sidecar和receive区别?

Thanos Sidecar 和 Thanos Receive 是 Thanos 生态系统中两个关键组件&#xff0c;但它们在架构中的作用和功能上有明显的区别。以下是它们的主要区别&#xff1a; 1. Thanos Sidecar 功能&#xff1a; 与 Prometheus 集成&#xff1a; Sidecar 是一个部署在每个 Prometheus…

Unity入门笔记(缘更)

内容来源SiKi学院的Luna’s Fantasy 文章目录 一、基础知识1.准备2.基础知识1.层级(Layer)2.轴心点3.预制体(Prefab)4.刚体组件(Rigidbody)5.碰撞器组件(BoxCollider) 二、代码1.移动 一、基础知识 1.准备 Unity安装&#xff1a; https://unity.cn 2.基础知识 1.层级(Layer…

使用VHD虚拟磁盘安装双系统,避免磁盘分区

前言 很多时候&#xff0c;我们对现在的操作系统不满意,就想要自己安装一个双系统 但是安装双系统又涉及到硬盘分区,非常复杂,容易造成数据问题 虚拟机的话有经常用的不爽,这里其实有一个介于虚拟机和双系统之间的解决方法,就是使用虚拟硬盘文件安装系统. 相当于系统在机上…

ARINC818协议(五)

1.R_CTL,设置固定的0x44即可 2.Dest_ID:目的地D_ID,如果不需要目的地址&#xff0c;就设置为0&#xff1b;ADVB协议支持 多个视频目的地址&#xff0c;广播通信; 3.cs_ctl在FC-AV上不用 4.source_ID:S_ID [23:0]包含源实体的端口的地址标识&#xff1b;不用就设置为0. ADVB允许…

鸿蒙开发对于RelativeContainer高度设置‘auto‘后还是没有自适应问题的解决方案

RelativeContainer设置高度为自适应‘auto’没用生效&#xff0c;查看了官方文档(文档中心)也没用给出明确的答案。只说了不能把锚点设置成父组件锚点&#xff08;__container__&#xff09;。也尝试了使用guidline来替换父组件锚点&#xff0c;还是没能自适应高度。 后来尝试让…

k8s教程3:Kubernetes应用的部署和管理

学习目标 理解Kubernetes中应用部署的基本概念和方法掌握Deployment、ReplicaSet、StatefulSet、DaemonSet、Job与CronJob等控制器的使用了解Helm作为Kubernetes的包管理工具的基本使用通过实际示例学习应用的部署、更新与管理 Kubernetes提供了一套强大而灵活的机制&#xff…

通过特定协议拉起 electron 应用

在 Android 通过 sheme 协议可以拉起其他应用。 electron 应用也可以通过类似特定协议被拉起。 在同时有 web、客户端的应用里&#xff0c;可以通过这种方式在 web 拉起客户端。 支持拉起客户端 const PROTOCOL xxxif (process.defaultApp) {// 这里是开发环境&#xff0c;有…

算法备案的审核标准是什么?

随着《互联网信息服务算法推荐管理规定》等法规的出台&#xff0c;算法备案成为了强制性备案&#xff0c;是产品合规上线的必要条件之一。本篇内容将从企业视角出发&#xff0c;分析算法备案的常见问题&#xff0c;意在对有备案需求的小伙伴们有所帮助。 一、谁需要做算法备案…

回顾与动机 - 为什么我们需要 Transformer

在接下来的旅程中,我们将一起探索深度学习领域最重要、最具影响力的模型架构之一——Transformer。从它的基本原理出发,逐步深入,最终能够亲手实现一个文本生成模型。 本系列教程假设你已经具备一定的深度学习基础,了解神经网络、损失函数、优化器等基本概念,并且熟悉 Py…