【发布时间】:2019-09-20 06:57:36
【问题描述】:
我试图弄清楚在操作系统的最低级别是如何分配内存的。据我所知,操作系统只是在记录可用和不可用的内存,而 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 并没有找到任何东西。
【问题讨论】:
-
现在,最低级别是virtual memory manager。
-
我想在开始分页之前实现这个。
-
请注意
char * ptr = malloc(5); printf("The memory address for this pointer is at: %d\n", &ptr);不正确有两个原因:错误的格式说明符,它传递的是指针的位置,而不是它的值。应该是printf("%p\n", (void*)ptr); -
在某些系统中,您可能会“逃避”使用错误的格式说明符,但通常情况下,如果
int*占用 8 个字节而int占用 4 个字节,您将不会不要报告正确的地址。
标签: c memory memory-management x86 operating-system