简体   繁体   English

内存分配在操作系统的最低级别如何发生?

[英]How does memory allocation happen at the lowest level in an operating system?

I'm trying to figure out how memory is allocated at the lowest level in an operating system. 我试图弄清楚如何在操作系统的最低级别分配内存。 From what I can gather is that the operating system is just doing the book keeping of the memory that is available and not available, and it is the C programming language that will do the allocation at the lowest level. 据我所知,操作系统只是在对可用内存和不可用内存进行记账,而C编程语言将在最低级别进行分配。

So, the first example is what I came up with as a simple memory allocation system, and then I took an example from the following resource: https://github.com/levex/osdev . 因此,第一个示例是我作为一个简单的内存分配系统想到的,然后从以下资源中举了一个示例: https : //github.com/levex/osdev

Example-1: 示例1:

    struct heap_elements {
        int start_address;
        int end_address;
        int size;
        int reservation;
    };

    struct heap_elements heap[25];

    // Write len copies of val into dest.
    void memset(int *dest, int val, int len)
    {
        int *temp = (int *)dest;
        for ( ; len != 0; len--) *temp++ = val;
    }

    /*
    * This function will take a source and destination and copy n amount
    * - of bytes from the source to the destination address. 
    */ 
    void memory_copy(unsigned char *source, unsigned char *destination, int bytes) {
        for (int i = 0; i < bytes; i++) {
            *(destination + i) = *(source + i);
        }
    }

    int find_memory_hole(int size) {

        for (int i = 0; i < total_elements; i++) {
            if (heap[i].reservation == 0) {
                if (heap[i].size >= size || heap[i].size == 0) {
                return i;
                }
            }
        }
        return -1;
    }

    int * malloc(int size) {   
        int hole = find_memory_hole(size);
        if (hole != -1) {
            if (heap[hole].start_address == 0) {
                heap[hole].start_address = ending_address;
                ending_address += size;
                heap[hole].end_address = ending_address;
                heap[hole].size = size;
                heap[hole].reservation = 1;
                kprintf("Starting address: %d\n", heap[hole].start_address);
                kprintf("Ending address: %d\n", heap[hole].end_address);
            } else {
                heap[hole].size = size;
                heap[hole].reservation = 1;
            }
            memset((int*)heap[hole].start_address, 0, size);
            return (int*)heap[hole].start_address;
        } else {
            kprintf("FREE SOME MEMORY~!\n");
            kprintf("WE NEED ROOM IN HERE~!\n");
            return 0;
        }
    }

    void heap_install() {
        total_elements = 25;
        starting_address = 0x100000;  // 1 - MB
        ending_address = 0x100000;    // 1 - MB
        max_memory_address = 0xEEE00000;  // 4 - GB

        for (int i = 0; i < total_elements; i++) {
            heap[i].start_address = 0;
            heap[i].end_address = 0;
            heap[i].size = 0;
            heap[i].reservation = 0;
        }

        return;
    }

    void free(void * pointer) {

        int memory_found = 0;
        kprintf("Address %d\n", &pointer);
        int memory_address = &pointer;

        for (int i = 0; i < total_elements; i++) {
            if (heap[i].start_address == memory_address) {
                heap[i].size = 0;
                heap[i].reservation = 0;
                memory_found = 1;
                break;
            }
        }

        if (memory_found == 0)
            kprintf("Memory could not bee free'd (NOT FOUND).\n");

        return;
    }

Example-2: 示例2:

    void mm_init(unsigned kernel_end)
    {
        kprintf("The kernel end is: %d\n", kernel_end);
        last_alloc = kernel_end + 0x1000;   // Set our starting point.
        heap_begin = last_alloc;
        heap_end = 0x5B8D80;                // Set the bar to 6 MB
        memset((char *)heap_begin, 0, heap_end - heap_begin);
    }

    void mm_print_out()
    {
        kprintf("Memory used: %d bytes\n", memory_used);
        kprintf("Memory free: %d bytes\n", heap_end - heap_begin - memory_used);
        kprintf("Heap size: %d bytes\n", heap_end - heap_begin);
        kprintf("Heap start: 0x%x\n", heap_begin);
        kprintf("Heap end: 0x%x\n", heap_end);
    }

    void free(void *mem)
    {
        alloc_t *alloc = (mem - sizeof(alloc_t));
        memory_used -= alloc->size + sizeof(alloc_t);
        alloc->status = 0;
    }

    char* malloc(unsigned size)
    {
        if(!size) return 0;

        /* Loop through blocks and find a block sized the same or bigger */
        unsigned char *mem = (unsigned char *)heap_begin;
        while((unsigned)mem < last_alloc)
        {
            alloc_t *a = (alloc_t *)mem;
            /* If the alloc has no size, we have reaced the end of allocation */

            if(!a->size)
                goto nalloc;
            /* If the alloc has a status of 1 (allocated), then add its size
            * and the sizeof alloc_t to the memory and continue looking.
            */
            if(a->status) {
                mem += a->size;
                mem += sizeof(alloc_t);
                mem += 4;
                continue;
            }
            /* If the is not allocated, and its size is bigger or equal to the
            * requested size, then adjust its size, set status and return the location.
            */
            if(a->size >= size)
            {
                /* Set to allocated */
                a->status = 1;
                memset(mem + sizeof(alloc_t), 0, size);
                memory_used += size + sizeof(alloc_t);
                return (char *)(mem + sizeof(alloc_t));
            }
            /* If it isn't allocated, but the size is not good, then
            * add its size and the sizeof alloc_t to the pointer and
            * continue;
            */
            mem += a->size;
            mem += sizeof(alloc_t);
            mem += 4;
        }

        nalloc:;
        if(last_alloc+size+sizeof(alloc_t) >= heap_end)
        {
            panic("From Memory.c", "Something", 0);
        }
        alloc_t *alloc = (alloc_t *)last_alloc;
        alloc->status = 1;
        alloc->size = size;

        last_alloc += size;
        last_alloc += sizeof(alloc_t);
        last_alloc += 4;

        memory_used += size + 4 + sizeof(alloc_t);
        memset((char *)((unsigned)alloc + sizeof(alloc_t)), 0, size);
        return (char *)((unsigned)alloc + sizeof(alloc_t));

    }

From both examples I expected memory that I allocated from malloc() would have the same starting address as to where I allocated it at, if that makes sense? 从这两个示例中,我都希望从malloc()分配的内存与在其分配的位置具有相同的起始地址,如果有意义的话? If I know the end of my kernel is at the 0x9000 mark, and I want to start allocating memory at the 1 MB mark. 如果我知道内核的末尾是0x9000标记,那么我想开始以1 MB标记分配内存。 Yes, I know where my kernel is in memory is weird and not conventional, but I know that memory is free past the 1 MB mark. 是的,我知道我的内核在内存中的位置很奇怪,而不是常规的,但是我知道超过1 MB标记后内存是可用的。

So, if I know the following: 因此,如果我知道以下内容:

kernel_end = 0x9000;
heap_starts = 0x100000;
heap_ends = 0x5B8D80;

I would expect that this: 我希望这:

char * ptr = malloc(5)

printf("The memory address for this pointer is at: %d\n", &ptr);

Would be near the 0x100000 memory address but it is not. 会在0x100000内存地址附近,但不是。 It is some where completely different and is the reason why I think that I'm not physically telling where the char pointer to be at in memory and that it is the C programming language putting it somewhere differently. 这是一些完全不同的地方,这也是为什么我认为我不是在物理上告诉char指针在内存中的位置,而是C语言将它放在不同的地方的原因。 I can't figure out what I am doing wrong and it shouldn't be this hard to understand this. 我无法弄清楚我在做什么错,理解这一点应该不难。 Also, I have looked in OSDev Wiki and haven't found anything. 另外,我已经查看了OSDev Wiki,但没有发现任何东西。

I'm trying to figure out how memory is allocated at the lowest level in an operating system. 我试图弄清楚如何在操作系统的最低级别分配内存。 From what I can gather is that the operating system is just doing the book keeping of the memory that is available and not available, and it is the C programming language that will do the allocation at the lowest level. 据我所知,操作系统只是在对可用内存和不可用内存进行记账,而C编程语言将在最低级别进行分配。

The OS certainly does do bookkeeping for what memory is available and what not, but putting it in those terms vastly oversimplifies, and I suspect you have a different idea of what "memory" means here than best fits. 操作系统当然会为可用内存和不可用内存进行簿记,但是用这些术语将其大大简化了,我怀疑您对“内存”在这里的含义和最合适的含义有所不同。

The OS's virtual memory management subsystem manages how physical memory and other storage resources, such as disk-based swap space, are mapped to each process's virtual address space, including how much and which parts of a process's virtual address space maps to usable memory. 操作系统的虚拟内存管理子系统管理如何将物理内存和其他存储资源(例如基于磁盘的交换空间)映射到每个进程的虚拟地址空间,包括进程的虚拟地址空间中有多少以及哪些部分映射到可用内存。 It serves requests to increase and decrease a process's available virtual memory, as well as explicit requests to create memory mappings, such as those based on ordinary files. 它服务于增加或减少进程的可用虚拟内存的请求,以及创建内存映射(例如基于普通文件的内存映射)的显式请求。

As far as servicing malloc() calls in a userspace program, you are more or less correct. 至于为用户空间程序中的malloc()调用提供服务,您或多或少是正确的。 Programs generally obtain memory from the OS in sizeable blocks, which malloc() , free() , and friends carve up and manage. 程序通常从操作系统中以较大的块获取内存,而malloc()free()和朋友则分担并管理这些块。 Typically, those details involve the kernel only when the process fills up the memory already available to it, and needs to request more from the kernel. 通常,只有当进程填满了已经可用的内存,并且需要从内核请求更多信息时,这些细节才涉及内核。

But the lowest level is definitely in the kernel. 但是最低级别肯定在内核中。 The C library's memory-management functions can work only with memory allocated to the process by the OS. C库的内存管理功能只能与OS分配给进程的内存一起使用。

From both examples I expected memory that I allocated from malloc() would have the same starting address as to where I allocated it at, if that makes sense? 从这两个示例中,我都希望从malloc()分配的内存与在其分配的位置具有相同的起始地址,如果有意义的话? If I know the end of my kernel is at the 0x9000 mark, and I want to start allocating memory at the 1 MB mark. 如果我知道内核的末尾是0x9000标记,那么我想开始以1 MB标记分配内存。 Yes, I know where my kernel is in memory is weird and not conventional, but I know that memory is free past the 1 MB mark. 是的,我知道我的内核在内存中的位置很奇怪,而不是常规的,但是我知道超过1 MB标记后内存是可用的。

The kernel's view of memory is different from userspace processes'. 内核的内存视图不同于用户空间进程。 Each process runs in its own virtual address space, without any visibility into which physical addresses it is using. 每个进程都在其自己的虚拟地址空间中运行,无法查看其使用的物理地址。

I'm trying to figure out how memory is allocated at the lowest level in an operating system. 我试图弄清楚如何在操作系统的最低级别分配内存。

Your problem is that you are not looking at how the operating system allocates memory. 您的问题是您没有查看操作系统如何分配内存。 You are looking at application level memory allocation. 您正在查看应用程序级别的内存分配。

For processes, the operating system only allocates memory in PAGES. 对于进程,操作系统仅在PAGES中分配内存。 A process gains more memory by calling a system service that maps more pages into the process address (ie makes more pages valid). 进程通过调用将更多页面映射到进程地址(即,使更多页面有效)的系统服务来获取更多内存。

Because applications usually need memory allocations smaller than a page (for things like strings), heap management functions are often used. 由于应用程序通常需要小于页面的内存分配(对于诸如字符串之类的东西),因此经常使用堆管理功能。 malloc and free are rarely (if ever) operating system services.The are simply functions that can allocate memory in increments smaller than a page. malloc和free很少(如果有的话)是操作系统服务。这些简单的函数可以以小于页面的增量分配内存。

Typically, a call to malloc results in the function trying to find a block of memory large enough to return to the caller. 通常,对malloc的调用会导致该函数尝试查找足够大的内存块以返回给调用者。 If such a block is not available, malloc will call the operating system service to map pages into the address space to increase the amount of available memory in the heap so that it can return a large enough block of memory. 如果此类块不可用,则malloc将调用操作系统服务以将页面映射到地址空间,以增加堆中的可用内存量,以便它可以返回足够大的内存块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM