[英]How does memory allocation happen at the lowest level in an operating system?
我試圖弄清楚如何在操作系統的最低級別分配內存。 據我所知,操作系統只是在對可用內存和不可用內存進行記賬,而C編程語言將在最低級別進行分配。
因此,第一個示例是我作為一個簡單的內存分配系統想到的,然后從以下資源中舉了一個示例: https : //github.com/levex/osdev 。
示例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;
}
示例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));
}
從這兩個示例中,我都希望從malloc()分配的內存與在其分配的位置具有相同的起始地址,如果有意義的話? 如果我知道內核的末尾是0x9000標記,那么我想開始以1 MB標記分配內存。 是的,我知道我的內核在內存中的位置很奇怪,而不是常規的,但是我知道超過1 MB標記后內存是可用的。
因此,如果我知道以下內容:
kernel_end = 0x9000;
heap_starts = 0x100000;
heap_ends = 0x5B8D80;
我希望這:
char * ptr = malloc(5)
printf("The memory address for this pointer is at: %d\n", &ptr);
會在0x100000內存地址附近,但不是。 這是一些完全不同的地方,這也是為什么我認為我不是在物理上告訴char指針在內存中的位置,而是C語言將它放在不同的地方的原因。 我無法弄清楚我在做什么錯,理解這一點應該不難。 另外,我已經查看了OSDev Wiki,但沒有發現任何東西。
我試圖弄清楚如何在操作系統的最低級別分配內存。 據我所知,操作系統只是在對可用內存和不可用內存進行記賬,而C編程語言將在最低級別進行分配。
操作系統當然會為可用內存和不可用內存進行簿記,但是用這些術語將其大大簡化了,我懷疑您對“內存”在這里的含義和最合適的含義有所不同。
操作系統的虛擬內存管理子系統管理如何將物理內存和其他存儲資源(例如基於磁盤的交換空間)映射到每個進程的虛擬地址空間,包括進程的虛擬地址空間中有多少以及哪些部分映射到可用內存。 它服務於增加或減少進程的可用虛擬內存的請求,以及創建內存映射(例如基於普通文件的內存映射)的顯式請求。
至於為用戶空間程序中的malloc()
調用提供服務,您或多或少是正確的。 程序通常從操作系統中以較大的塊獲取內存,而malloc()
, free()
和朋友則分擔並管理這些塊。 通常,只有當進程填滿了已經可用的內存,並且需要從內核請求更多信息時,這些細節才涉及內核。
但是最低級別肯定在內核中。 C庫的內存管理功能只能與OS分配給進程的內存一起使用。
從這兩個示例中,我都希望從malloc()分配的內存與在其分配的位置具有相同的起始地址,如果有意義的話? 如果我知道內核的末尾是0x9000標記,那么我想開始以1 MB標記分配內存。 是的,我知道我的內核在內存中的位置很奇怪,而不是常規的,但是我知道超過1 MB標記后內存是可用的。
內核的內存視圖不同於用戶空間進程。 每個進程都在其自己的虛擬地址空間中運行,無法查看其使用的物理地址。
我試圖弄清楚如何在操作系統的最低級別分配內存。
您的問題是您沒有查看操作系統如何分配內存。 您正在查看應用程序級別的內存分配。
對於進程,操作系統僅在PAGES中分配內存。 進程通過調用將更多頁面映射到進程地址(即,使更多頁面有效)的系統服務來獲取更多內存。
由於應用程序通常需要小於頁面的內存分配(對於諸如字符串之類的東西),因此經常使用堆管理功能。 malloc和free很少(如果有的話)是操作系統服務。這些簡單的函數可以以小於頁面的增量分配內存。
通常,對malloc的調用會導致該函數嘗試查找足夠大的內存塊以返回給調用者。 如果此類塊不可用,則malloc將調用操作系統服務以將頁面映射到地址空間,以增加堆中的可用內存量,以便它可以返回足夠大的內存塊。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.