Я пытаюсь выяснить, как выделяется память на самом низком уровне в операционной системе.Из того, что я могу понять, является то, что операционная система просто ведет учет памяти, которая доступна и недоступна, и это язык программирования C, который будет выполнять распределение на самом низком уровне.
Итак, первый пример - это то, что я придумал как простая система выделения памяти, а затем я взял пример из следующего ресурса: https://github.com/levex/osdev.
Example-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 МБ.Да, я знаю, где находится мое ядро в памяти, странно и не совсем обычно, но я знаю, что память свободна после отметки в 1 МБ.
Итак, если я знаю следующее:
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, но это не так.Это кое-где совершенно иное, и поэтому я думаю, что я физически не говорю, где указатель на символ должен находиться в памяти, и что это язык программирования C, где-то иначе.Я не могу понять, что я делаю неправильно, и это не должно быть так сложно понять.Также я заглянул в OSDev Wiki и ничего не нашел.