69天探索操作系统-第15天:内存管理概述和内存层次结构

245 阅读9分钟

Pro6.avif

1.介绍

内存管理是操作系统设计中的一个关键方面,负责处理计算机内存的组织和管理。它涉及各种机制,以高效地将内存分 配给进程、管理不同类型的内存以及在保持系统稳定的同时确保最佳性能。

2.内存层次结构架构

内存层次结构被设计为在成本、速度和容量之间达到平衡。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define CACHE_L1_SIZE 32
#define CACHE_L2_SIZE 256
#define MAIN_MEMORY_SIZE 1024
#define VIRTUAL_MEMORY_SIZE 4096

typedef struct {
    int data;
    int address;
    int valid;
    int access_time;
} MemoryBlock;

typedef struct {
    MemoryBlock l1_cache[CACHE_L1_SIZE];
    MemoryBlock l2_cache[CACHE_L2_SIZE];
    MemoryBlock main_memory[MAIN_MEMORY_SIZE];
    MemoryBlock virtual_memory[VIRTUAL_MEMORY_SIZE];
    
    int l1_hits;
    int l1_misses;
    int l2_hits;
    int l2_misses;
    int page_faults;
} MemoryHierarchy;

// Initialize memory hierarchy
void initializeMemory(MemoryHierarchy *mh) {
    // Initialize L1 Cache
    for(int i = 0; i < CACHE_L1_SIZE; i++) {
        mh->l1_cache[i].valid = 0;
        mh->l1_cache[i].access_time = 1; // 1 cycle
    }
    
    // Initialize L2 Cache
    for(int i = 0; i < CACHE_L2_SIZE; i++) {
        mh->l2_cache[i].valid = 0;
        mh->l2_cache[i].access_time = 10; // 10 cycles
    }
    
    // Initialize Main Memory
    for(int i = 0; i < MAIN_MEMORY_SIZE; i++) {
        mh->main_memory[i].valid = 0;
        mh->main_memory[i].access_time = 100; // 100 cycles
    }
    
    // Initialize Virtual Memory
    for(int i = 0; i < VIRTUAL_MEMORY_SIZE; i++) {
        mh->virtual_memory[i].valid = 0;
        mh->virtual_memory[i].access_time = 1000; // 1000 cycles
    }
    
    mh->l1_hits = 0;
    mh->l1_misses = 0;
    mh->l2_hits = 0;
    mh->l2_misses = 0;
    mh->page_faults = 0;
}

// Memory access function
int accessMemory(MemoryHierarchy *mh, int address, int data) {
    int total_time = 0;
    
    // Check L1 Cache
    int l1_index = address % CACHE_L1_SIZE;
    if(mh->l1_cache[l1_index].valid && mh->l1_cache[l1_index].address == address) {
        mh->l1_hits++;
        total_time += mh->l1_cache[l1_index].access_time;
        return total_time;
    }
    
    mh->l1_misses++;
    
    // Check L2 Cache
    int l2_index = address % CACHE_L2_SIZE;
    if(mh->l2_cache[l2_index].valid && mh->l2_cache[l2_index].address == address) {
        mh->l2_hits++;
        // Update L1 Cache
        mh->l1_cache[l1_index].data = mh->l2_cache[l2_index].data;
        mh->l1_cache[l1_index].address = address;
        mh->l1_cache[l1_index].valid = 1;
        
        total_time += mh->l2_cache[l2_index].access_time;
        return total_time;
    }
    
    mh->l2_misses++;
    
    // Check Main Memory
    int mm_index = address % MAIN_MEMORY_SIZE;
    if(mh->main_memory[mm_index].valid && mh->main_memory[mm_index].address == address) {
        // Update L1 and L2 Cache
        mh->l1_cache[l1_index].data = mh->main_memory[mm_index].data;
        mh->l1_cache[l1_index].address = address;
        mh->l1_cache[l1_index].valid = 1;
        
        mh->l2_cache[l2_index].data = mh->main_memory[mm_index].data;
        mh->l2_cache[l2_index].address = address;
        mh->l2_cache[l2_index].valid = 1;
        
        total_time += mh->main_memory[mm_index].access_time;
        return total_time;
    }
    
    // Page Fault - Access Virtual Memory
    mh->page_faults++;
    int vm_index = address % VIRTUAL_MEMORY_SIZE;
    
    // Update all levels of memory
    mh->main_memory[mm_index].data = mh->virtual_memory[vm_index].data;
    mh->main_memory[mm_index].address = address;
    mh->main_memory[mm_index].valid = 1;
    
    mh->l2_cache[l2_index].data = mh->virtual_memory[vm_index].data;
    mh->l2_cache[l2_index].address = address;
    mh->l2_cache[l2_index].valid = 1;
    
    mh->l1_cache[l1_index].data = mh->virtual_memory[vm_index].data;
    mh->l1_cache[l1_index].address = address;
    mh->l1_cache[l1_index].valid = 1;
    
    total_time += mh->virtual_memory[vm_index].access_time;
    return total_time;
}

// Print memory statistics
void printMemoryStats(MemoryHierarchy *mh) {
    printf("\nMemory Access Statistics:\n");
    printf("L1 Cache Hits: %d\n", mh->l1_hits);
    printf("L1 Cache Misses: %d\n", mh->l1_misses);
    printf("L2 Cache Hits: %d\n", mh->l2_hits);
    printf("L2 Cache Misses: %d\n", mh->l2_misses);
    printf("Page Faults: %d\n", mh->page_faults);
    
    float l1_hit_ratio = (float)mh->l1_hits / (mh->l1_hits + mh->l1_misses);
    float l2_hit_ratio = (float)mh->l2_hits / (mh->l2_hits + mh->l2_misses);
    
    printf("\nCache Performance:\n");
    printf("L1 Hit Ratio: %.2f%%\n", l1_hit_ratio * 100);
    printf("L2 Hit Ratio: %.2f%%\n", l2_hit_ratio * 100);
}

int main() {
    MemoryHierarchy mh;
    initializeMemory(&mh);
    
    // Simulate memory accesses
    srand(time(NULL));
    int total_accesses = 1000;
    int total_time = 0;
    
    for(int i = 0; i < total_accesses; i++) {
        int address = rand() % VIRTUAL_MEMORY_SIZE;
        int data = rand() % 1000;
        total_time += accessMemory(&mh, address, data);
    }
    
    printMemoryStats(&mh);
    printf("\nTotal Access Time: %d cycles\n", total_time);
    printf("Average Access Time: %.2f cycles\n", (float)total_time / total_accesses);
    
    return 0;
}.

3.内存类型及其特征

每种内存类型都有其特定的特征,会影响系统的性能:

  • 寄存器:时间最短的内存类型,每秒1个周期。位于CPU内部。通常大小为32或64位,用于立即CPU操作。
  • 缓存内存:基于高速SRAM的内存。位于CPU和主存储器之间。分多个级别(L1、L2L3)组织。访问时间:L1(1-3周期)、L2(10-20周期)、L3(20-50周期)。
  • 主存储器(RAM):用于活跃进程的初级存储。使用DRAM技术。访问时间约为100-200周期。数据在断电时丢失的易失性存储。
  • 虚拟内存:使用磁盘空间扩展物理内存的扩展。提供比物理内存更大的地址空间。访问时间以千周期计。通过分页和段划分管理。

image.png

看看如下例子:

#include <stdio.h>
#include <stdlib.h>

#define REGISTER_SIZE 64
#define CACHE_LINE_SIZE 64
#define PAGE_SIZE 4096

typedef struct {
    int size_bits;
    int access_time_cycles;
    float cost_per_byte;
    int volatile_storage;
    char *type_name;
} MemoryCharacteristics;

void printMemoryCharacteristics(MemoryCharacteristics *mc) {
    printf("Memory Type: %s\n", mc->type_name);
    printf("Size (bits): %d\n", mc->size_bits);
    printf("Access Time (cycles): %d\n", mc->access_time_cycles);
    printf("Cost per byte: $%.2f\n", mc->cost_per_byte);
    printf("Volatile: %s\n\n", mc->volatile_storage ? "Yes" : "No");
}

int main() {
    MemoryCharacteristics memories[] = {
        {REGISTER_SIZE, 1, 100.0, 1, "CPU Register"},
        {CACHE_LINE_SIZE, 3, 50.0, 1, "L1 Cache"},
        {CACHE_LINE_SIZE * 8, 10, 25.0, 1, "L2 Cache"},
        {PAGE_SIZE, 100, 1.0, 1, "Main Memory"},
        {PAGE_SIZE * 1024, 10000, 0.1, 0, "Virtual Memory"}
    };
    
    int num_memories = sizeof(memories) / sizeof(MemoryCharacteristics);
    
    for(int i = 0; i < num_memories; i++) {
        printMemoryCharacteristics(&memories[i]);
    }
    
    return 0;
}

4.内存管理技术

C代码示例:首次适应内存分配

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MEMORY_SIZE 1024
#define MIN_BLOCK_SIZE 16

typedef struct MemoryBlock {
    size_t size;
    int is_allocated;
    struct MemoryBlock* next;
    struct MemoryBlock* prev;
} MemoryBlock;

typedef struct {
    void* memory;
    MemoryBlock* free_list;
    size_t total_size;
    size_t used_size;
} MemoryManager;

// Initialize memory manager
MemoryManager* initializeMemoryManager(size_t size) {
    MemoryManager* manager = (MemoryManager*)malloc(sizeof(MemoryManager));
    manager->memory = malloc(size);
    manager->total_size = size;
    manager->used_size = 0;
    
    // Initialize free list with single block
    manager->free_list = (MemoryBlock*)manager->memory;
    manager->free_list->size = size - sizeof(MemoryBlock);
    manager->free_list->is_allocated = 0;
    manager->free_list->next = NULL;
    manager->free_list->prev = NULL;
    
    return manager;
}

// Allocate memory using First Fit
void* memoryAlloc(MemoryManager* manager, size_t size) {
    MemoryBlock* current = manager->free_list;
    
    while(current != NULL) {
        if(!current->is_allocated && current->size >= size) {
            // Split block if possible
            if(current->size >= size + sizeof(MemoryBlock) + MIN_BLOCK_SIZE) {
                MemoryBlock* new_block = (MemoryBlock*)((char*)current + sizeof(MemoryBlock) + size);
                new_block->size = current->size - size - sizeof(MemoryBlock);
                new_block->is_allocated = 0;
                new_block->next = current->next;
                new_block->prev = current;
                
                if(current->next != NULL) {
                    current->next->prev = new_block;
                }
                
                current->next = new_block;
                current->size = size;
            }
            
            current->is_allocated = 1;
            manager->used_size += current->size + sizeof(MemoryBlock);
            
            return (void*)((char*)current + sizeof(MemoryBlock));
        }
        current = current->next;
    }
    
    return NULL;
}

// Free allocated memory
void memoryFree(MemoryManager* manager, void* ptr) {
    if(ptr == NULL) return;
    
    MemoryBlock* block = (MemoryBlock*)((char*)ptr - sizeof(MemoryBlock));
    block->is_allocated = 0;
    manager->used_size -= block->size + sizeof(MemoryBlock);
    
    // Merge with next block if free
    if(block->next != NULL && !block->next->is_allocated) {
        block->size += block->next->size + sizeof(MemoryBlock);
        block->next = block->next->next;
        if(block->next != NULL) {
            block->next->prev = block;
        }
    }
    
    // Merge with previous block if free
    if(block->prev != NULL && !block->prev->is_allocated) {
        block->prev->size += block->size + sizeof(MemoryBlock);
        block->prev->next = block->next;
        if(block->next != NULL) {
            block->next->prev = block->prev;
        }
    }
}

// Print memory state
void printMemoryState(MemoryManager* manager) {
    MemoryBlock* current = manager->free_list;
    int block_count = 0;
    
    printf("\nMemory State:\n");
    printf("Total Size: %zu bytes\n", manager->total_size);
    printf("Used Size: %zu bytes\n", manager->used_size);
    printf("Free Size: %zu bytes\n", manager->total_size - manager->used_size);
    
    while(current != NULL) {
        printf("Block %d: Size=%zu, %s\n", 
               block_count++, 
               current->size, 
               current->is_allocated ? "Allocated" : "Free");
        current = current->next;
    }
}

int main() {
    MemoryManager* manager = initializeMemoryManager(MEMORY_SIZE);
    
    // Test memory allocation and deallocation
    void* ptr1 = memoryAlloc(manager, 128);
    void* ptr2 = memoryAlloc(manager, 256);
    void* ptr3 = memoryAlloc(manager, 64);
    
    printMemoryState(manager);
    
    memoryFree(manager, ptr2);
    memoryFree(manager, ptr1);
    memoryFree(manager, ptr3);
    
    printMemoryState(manager);
    
    free(manager->memory);
    free(manager);
    
    return 0;
}

image.png

5.缓存内存管理

缓存内存管理涉及:

  • 缓存组织:直接映射缓存、集合映射缓存、完全映射缓存。
  • 缓存替换策略:LRU(最近最少使用),FIFO(先进先出),随机替换。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define CACHE_SIZE 256
#define BLOCK_SIZE 64
#define NUM_SETS 4

typedef struct {
    int valid;
    int tag;
    int data;
    int last_used;
} CacheLine;

typedef struct {
    CacheLine* lines;
    int num_sets;
    int blocks_per_set;
    int access_count;
    int hits;
    int misses;
} Cache;

Cache* initializeCache() {
    Cache* cache = (Cache*)malloc(sizeof(Cache));
    cache->num_sets = NUM_SETS;
    cache->blocks_per_set = CACHE_SIZE / (BLOCK_SIZE * NUM_SETS);
    cache->lines = (CacheLine*)calloc(CACHE_SIZE / BLOCK_SIZE, sizeof(CacheLine));
    cache->access_count = 0;
    cache->hits = 0;
    cache->misses = 0;
    return cache;
}

int accessCache(Cache* cache, int address) {
    int set_index = (address / BLOCK_SIZE) % cache->num_sets;
    int tag = address / (BLOCK_SIZE * cache->num_sets);
    int set_start = set_index * cache->blocks_per_set;
    int found = 0;
    
    cache->access_count++;
    
    // Look for hit
    for(int i = 0; i < cache->blocks_per_set; i++) {
        int line_index = set_start + i;
        if(cache->lines[line_index].valid && cache->lines[line_index].tag == tag) {
            cache->hits++;
            cache->lines[line_index].last_used = cache->access_count;
            found = 1;
            break;
        }
    }
    
    if(!found) {
        cache->misses++;
        // Find LRU line
        int lru_index = set_start;
        int lru_time = cache->lines[set_start].last_used;
        
        for(int i = 1; i < cache->blocks_per_set; i++) {
            int line_index = set_start + i;
            if(!cache->lines[line_index].valid || 
               cache->lines[line_index].last_used < lru_time) {
                lru_index = line_index;
                lru_time = cache->lines[line_index].last_used;
            }
        }
        
        // Replace line
        cache->lines[lru_index].valid = 1;
        cache->lines[lru_index].tag = tag;
        cache->lines[lru_index].last_used = cache->access_count;
    }
    
    return found;
}

void printCacheStats(Cache* cache) {
    printf("\nCache Statistics:\n");
    printf("Total Accesses: %d\n", cache->access_count);
    printf("Cache Hits: %d\n", cache->hits);
    printf("Cache Misses: %d\n", cache->misses);
    printf("Hit Rate: %.2f%%\n", 
           (float)cache->hits / cache->access_count * 100);
}

int main() {
    Cache* cache = initializeCache();
    srand(time(NULL));
    
    // Simulate memory accesses
    for(int i = 0; i < 1000; i++) {
        int address = rand() % (CACHE_SIZE * 4); // Simulate larger address space
        accessCache(cache, address);
    }
    
    printCacheStats(cache);
    
    free(cache->lines);
    free(cache);
    
    return 0;
}

6.虚拟内存概念

#include <stdio.h>
#include <stdlib.h>

#define PAGE_SIZE 4096
#define NUM_PAGES 1024
#define FRAME_SIZE PAGE_SIZE
#define NUM_FRAMES 256

typedef struct {
    int valid;
    int frame_number;
    int referenced;
    int modified;
} PageTableEntry;

typedef struct {
    PageTableEntry* entries;
    int num_pages;
} PageTable;

typedef struct {
    void* memory;
    int num_frames;
    int* frame_status; // 0 = free, 1 = used
} PhysicalMemory;

PageTable* initializePageTable() {
    PageTable* pt = (PageTable*)malloc(sizeof(PageTable));
    pt->num_pages = NUM_PAGES;
    pt->entries = (PageTableEntry*)calloc(NUM_PAGES, sizeof(PageTableEntry));
    return pt;
}

PhysicalMemory* initializePhysicalMemory() {
    PhysicalMemory* pm = (PhysicalMemory*)malloc(sizeof(PhysicalMemory));
    pm->num_frames = NUM_FRAMES;
    pm->memory = malloc(NUM_FRAMES * FRAME_SIZE);
    pm->frame_status = (int*)calloc(NUM_FRAMES, sizeof(int));
    return pm;
}

int allocateFrame(PhysicalMemory* pm) {
    for(int i = 0; i < pm->num_frames; i++) {
        if(pm->frame_status[i] == 0) {
            pm->frame_status[i] = 1;
            return i;
        }
    }
    return -1; // No free frames
}

void* accessMemory(PageTable* pt, PhysicalMemory* pm, int virtual_address) {
    int page_number = virtual_address / PAGE_SIZE;
    int offset = virtual_address % PAGE_SIZE;
    
    if(page_number >= pt->num_pages) {
        printf("Invalid virtual address\n");
        return NULL;
    }
    
    PageTableEntry* pte = &pt->entries[page_number];
    
    if(!pte->valid) {
        // Page fault
        int frame = allocateFrame(pm);
        if(frame == -1) {
            printf("No free frames available\n");
            return NULL;
        }
        
        pte->valid = 1;
        pte->frame_number = frame;
        pte->referenced = 1;
        printf("Page fault handled: Page %d -> Frame %d\n", page_number, frame);
    }
    
    return (char*)pm->memory + (pte->frame_number * FRAME_SIZE) + offset;
}

int main() {
    PageTable* pt = initializePageTable();
    PhysicalMemory* pm = initializePhysicalMemory();
    
    // Test memory accesses
    for(int i = 0; i < 10; i++) {
        int virtual_address = rand() % (NUM_PAGES * PAGE_SIZE);
        void* physical_address = accessMemory(pt, pm, virtual_address);
        
        if(physical_address != NULL) {
            printf("Virtual Address: 0x%x -> Physical Address: %p\n", 
                   virtual_address, physical_address);
        }
    }
    
    free(pt->entries);
    free(pt);
    free(pm->frame_status);
    free(pm->memory);
    free(pm);
    
    return 0;
}

7. 内存保护机制

内存保护涉及:

  • 基址和界限寄存器
  • 内存密钥
  • 访问控制列表
  • 页面保护

8. 性能优化

关键优化技术:

  • 内存预取
  • 缓存行优化
  • 内存对齐
  • 页面着色

9.总结

内存管理是操作系统性能的基本要素。了解层次结构、保护机制和优化技术对于系统设计和实现至关重要。

10.参考资料和进一步阅读

  • Tanenbaum, A. S. (2015). Modern Operating Systems
  • Silberschatz, A. (2018). Operating System Concepts
  • Patterson, D. A., & Hennessy, J. L. (2017). Computer Organization and Design
  • Jacob, B., Ng, S. W., & Wang, D. (2010). Memory Systems: Cache, DRAM, Disk

进一步阅读:

  • "The Memory Hierarchy: A Tutorial" - ACM Computing Surveys
  • "Cache Optimization Techniques" - IEEE Transactions
  • "Virtual Memory Management in Modern Systems" - OS Research Journal