Files
cKit/Memory/c_Buddy.t.c
T

245 lines
8.0 KiB
C
Raw Normal View History

2026-08-29 00:53:40 +08:00
#include "c_Buddy.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdalign.h> // C11 標準
#include <c_Memory.h>
// 2. 測試用例函數宣告
void test_buddy_basic_alloc();
void test_buddy_alignment();
void test_buddy_oom();
void test_buddy_coalescing();
void test_1024(void);
int main(int argc, char** argv){
printf("--- 開始執行 c_Buddy_t 夥伴分配器測試 ---\n");
test_buddy_basic_alloc();
test_buddy_alignment();
test_buddy_oom();
test_buddy_coalescing();
test_1024();
printf("--- 所有測試用例通過! ---\n");
return 0;
}
void c_Buddy_PrintStatus(c_Buddy_t *b) {
if (!b || !b->head || !b->tail) {
printf("[Buddy] 錯誤:分配器尚未初始化或為空指標。\n");
return;
}
printf("\n=================== Buddy Allocator Status ===================\n");
printf("總記憶體範圍: %p ~ %p\n", (void*)b->head, (void*)b->tail);
printf("最小對齊基準 (Alignment): %d 位元組\n", b->alignment);
printf("--------------------------------------------------------------\n");
printf("%-5s | %-16s | %-12s | %-10s\n", "編號", "區塊記憶體位址", "區塊大小(Size)", "狀態");
printf("--------------------------------------------------------------\n");
c_BuddyBlock_t *curr = b->head;
int block_index = 0;
int total_free = 0;
int total_allocated = 0;
// 使用與之前相同的單指針步進遍歷
while (curr < b->tail) {
printf("[%3d] | %p | %-12d(%dKB) | %s\n",
block_index++,
(void*)curr,
curr->size,
curr->size/1024,
curr->is_free ? "FREE (空閒)" : "ALLOCATED (已佔用)");
if (curr->is_free) {
total_free += curr->size;
} else {
total_allocated += curr->size;
}
// 精確前進到下一個區塊
curr = (c_BuddyBlock_t *)((uint8_t *)curr + curr->size);
}
printf("--------------------------------------------------------------\n");
printf("摘要統計:已使用: %d 總位元組 | 剩餘空閒: %d 總位元組\n", total_allocated, total_free);
printf("==============================================================\n\n");
}
#define KB 1024
void test_1024(void) {
void* block = c_Memory_Aligned_Alloc(1024*KB, 8, __FILE__, __LINE__);
c_Buddy_t buddy;
c_Buddy_Init(&buddy, block, 1024*KB, 8);
printf("Step 1: Alloc A=70KB\n");
void* A = c_Buddy_Alloc(&buddy, 70*KB);
c_Buddy_PrintStatus(&buddy);
printf("Step 2: Alloc B=35KB\n");
void* B = c_Buddy_Alloc(&buddy, 35*KB);
c_Buddy_PrintStatus(&buddy);
printf("Step 3: Alloc C=80KB\n");
void* C = c_Buddy_Alloc(&buddy, 80*KB);
c_Buddy_PrintStatus(&buddy);
printf("Step 4: Free A\n");
c_Buddy_Free(&buddy, A);
c_Buddy_PrintStatus(&buddy);
printf("Step 5: Alloc D=60KB\n");
void* D = c_Buddy_Alloc(&buddy, 60*KB);
c_Buddy_PrintStatus(&buddy);
printf("Step 6: Free B\n");
c_Buddy_Free(&buddy, B);
c_Buddy_PrintStatus(&buddy);
printf("Step 7: Free D\n");
c_Buddy_Free(&buddy, D);
c_Buddy_PrintStatus(&buddy);
printf("Step 8: Free C\n");
c_Buddy_Free(&buddy, C);
c_Buddy_PrintStatus(&buddy);
printf("Step 9: Alloc E=600KB\n");
void* E = c_Buddy_Alloc(&buddy, 600*KB); // 实际分配 1024KB
c_Buddy_PrintStatus(&buddy);
printf("Step 10: Free E\n");
c_Buddy_Free(&buddy, E);
c_Buddy_PrintStatus(&buddy);
c_Memory_Aligned_Free(block, __FILE__, __LINE__);
}
// ==========================================
// 測試用例 1:基礎初始化與 2 的冪次方裂變分配
// ==========================================
void test_buddy_basic_alloc() {
printf("[測試] 基礎裂變分配...\n");
// 建立 1024 位元組的底層記憶體,對齊設為 8
uint8_t* backing_buffer = (uint8_t*)malloc(1024);
c_Buddy_t buddy;
c_Buddy_Init(&buddy, backing_buffer, 1024, 8);
assert(buddy.alignment == 8);
// 請求分配 120 位元組(夥伴系統通常會向上對齊到 128 或包含 Block Header 的 2 的冪次方)
void* p1 = c_Buddy_Alloc(&buddy, 120);
assert(p1 != NULL);
// 再次分配相同大小,地址應當緊鄰第一個區塊(按 2 冪次步進)
void* p2 = c_Buddy_Alloc(&buddy, 120);
assert(p2 != NULL);
assert(p2 > p1);
// 清理記憶體池內部分配
c_Buddy_Free(&buddy, p1);
c_Buddy_Free(&buddy, p2);
free(backing_buffer);
printf(" => 基礎分配測試成功\n");
}
// ==========================================
// 測試用例 2:記憶體對齊(Alignment)邊界驗證
// ==========================================
void test_buddy_alignment() {
printf("[測試] 記憶體對齊要求...\n");
uint8_t* backing_buffer = (uint8_t*)C_ALIGNED_ALLOC(2048, 64);
c_Buddy_t buddy;
// 強制對齊要求為 64 位元組
c_Buddy_Init(&buddy, backing_buffer, 2048, 64);
void* p1 = c_Buddy_Alloc(&buddy, 100);
void* p2 = c_Buddy_Alloc(&buddy, 100);
assert(p1 != NULL);
assert(p2 != NULL);
// 驗證返回的記憶體地址是否符合 64 位元組對齊
assert(((uintptr_t)p1 % 64) == 0);
assert(((uintptr_t)p2 % 64) == 0);
c_Buddy_Free(&buddy, p1);
c_Buddy_Free(&buddy, p2);
C_ALIGNED_FREE(backing_buffer);
printf(" => 對齊邊界測試成功\n");
}
// ==========================================
// 測試用例 3:記憶體溢出(OOM)
// ==========================================
void test_buddy_oom() {
printf("[測試] 記憶體溢出邊界...\n");
uint8_t* backing_buffer = (uint8_t*)malloc(512);
c_Buddy_t buddy;
c_Buddy_Init(&buddy, backing_buffer, 512, 8);
// 嘗試分配超出整塊夥伴系統大小的記憶體
void* p1 = c_Buddy_Alloc(&buddy, 600);
assert(p1 == NULL);
// 分配剛好極限的記憶體(需扣除或包含 Header 空間,依實作而定)
void* p2 = c_Buddy_Alloc(&buddy, 256);
assert(p2 != NULL);
void* p3 = c_Buddy_Alloc(&buddy, 256);
// 由於 512 已被完全填滿,此時應觸發 OOM
void* p4 = c_Buddy_Alloc(&buddy, 8);
assert(p4 == NULL);
if (p2) c_Buddy_Free(&buddy, p2);
if (p3) c_Buddy_Free(&buddy, p3);
free(backing_buffer);
printf(" => OOM 邊界測試成功\n");
}
// ==========================================
// 測試用例 4:核心邏輯——夥伴自動合併(Coalescing)
// ==========================================
// 說明:當 A 和 B 互為夥伴區塊,且 A 分配出去後,若 A 與 B 均被釋放,
// 夥伴系統必須將兩者合併回原本更大的 2 的冪次方區塊。
void test_buddy_coalescing() {
printf("[測試] 夥伴區塊自動合併(Coalescing...\n");
uint8_t* backing_buffer = (uint8_t*)malloc(1024);
c_Buddy_t buddy;
// 初始化一個 1024 總大小的區塊
c_Buddy_Init(&buddy, backing_buffer, 1024, 8);
// 1. 將其切碎:連續分配 4 個 256 的空間(假設總空間剛好能切 4 塊)
void* p1 = c_Buddy_Alloc(&buddy, 200); // 裂變為 256
void* p2 = c_Buddy_Alloc(&buddy, 200); // 裂變為 256
void* p3 = c_Buddy_Alloc(&buddy, 200); // 裂變為 256
void* p4 = c_Buddy_Alloc(&buddy, 200); // 裂變為 256
assert(p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL);
// 2. 此時剩餘空間為 0,嘗試分配 512 必然失敗
void* p_large_fail = c_Buddy_Alloc(&buddy, 500);
assert(p_large_fail == NULL);
// 3. 釋放相鄰的夥伴 p1 與 p2
c_Buddy_Free(&buddy, p1);
c_Buddy_Free(&buddy, p2);
// 4. 關鍵驗證:如果實作了自動合併,p1 和 p2 釋放後應融合成一個 512 的大區塊
// 此時再次申請 512 位元組(要求大小約 500),應該要能分配成功!
void* p_large_success = c_Buddy_Alloc(&buddy, 500);
assert(p_large_success != NULL);
// 清理剩餘記憶體
c_Buddy_Free(&buddy, p_large_success);
c_Buddy_Free(&buddy, p3);
c_Buddy_Free(&buddy, p4);
free(backing_buffer);
printf(" => 夥伴自動合併測試成功\n");
}