我有一个任务的自定义分配,几乎完成了。不幸的是,我遇到了一个我似乎无法诊断的问题。分配由执行缓存分配(< 2kB)和区域分配(> 2kB)的两个函数处理。这是我的内存结构:
23 typedef struct slab {
24 void *addr;
25 int bm[SLAB_SIZE/8/(8*sizeof(int))]; // bitmap for the slab
26 struct slab *next;
27 } slab;
40 typedef struct {
41 int alloc_unit;
42 slab S;
43 } cache;
46 typedef struct { // structure for the entire memory
47 cache C[9];
48 region *R;
49 } memory;
(注意:所有平板的位图大小相同,效率有点低,但我想让它首先像这样工作,而不是到处都有大量重复的代码)
问题在于相当复杂的 allocate_cache 函数,该函数适用于 8 字节以上的所有分配。我通过分配 50-100k 个 16B、32B、... 2kB 的实例对它进行了一些激烈的测试,一切正常。逻辑如下:每个都cache
包含一个slab
开头。每个都slab
可以有SLAB_SIZE/alloc_unit slots
,不同的slab不同(所以2kB的slab可以包含多达32个2kB内存的插槽,1kB的slab包含64个插槽,依此类推)。
这是我的分配缓存功能:
55 void *allocate_cache(unsigned int size) { // cache allocation
56
57 // 1. Select the cache
58 int ci = 0, si, pos, bmi; // cache_index, slot_index, position, bitmap index
59 int slbn = 0; // slab number
60 unsigned short check = 0;
61 while ((size-1) >> (ci+3))
62 ci++;
63 // 2. Find a slot
64 bmi = 0; // bitmap index
65 int lbmi = 0; // 'linked' bitmap index
66 int counter = 0;
67 int coefficient = SLAB_SIZE/M.C[ci].alloc_unit;
68 do {
69 pos = find_zero_bit(M.C[ci].S.bm[bmi]); // Find the first zero bit in the bitmap
70 if (pos == -1) { bmi++; // If bm[bmi] does not have free slots, keep checking the map...
71 if(bmi == coefficient/(8*sizeof(int))){ // If bmi is max size, then we need to check
72 slab *next_slab = &M.C[ci].S; // the following slabs, if there are any.
73 while(next_slab->next != NULL){ // While there are additional slabs
74 next_slab = next_slab->next;
75 slbn++; // Increment the slab counter.
76 while(lbmi < bmi) { // Go through the slots in this slab too
77 pos = find_zero_bit(next_slab->bm[lbmi]); // Until a free slot has been found
78 if(pos != -1) { // If a free slot has been found...
79 set_bit(&(next_slab->bm[lbmi]), pos); // Mark it as occupied...
80 check = 1;
81 break; // And break out of the loop.
82 }
83 lbmi++; counter++;
84 }
85 if(check == 1) break; // If we already found a free slot in one of the slots, break.
86 lbmi = 0;
87 }
88 }
89 }
90 else break;
91 } while(bmi < coefficient/(8*sizeof(int)));
92 si = bmi*32 + counter*32 + (pos - 1);
93 // compute the slot index based on bmi, pos and counter
94 // 3.a Slot not found => allocate a new slab
95 printf("pos = %d , si = %d, bmi = %d, slbn = %d lbmi = %d counter = %d\n", pos, si, bmi, slbn, lbmi, counter); // sanity check
96 if(pos == 32 && ((si+1) % coefficient == 0)) {
97 printf("===== SLAB FULL. NOW CREATING NEW SLAB. =====\n");
98 // Initialize a new slab.
99 slab *temp = &M.C[ci].S; // Set temp to the initially allocated slab
100 while(temp->next != NULL) temp = temp->next; // Get the last currently allocated slab
101 void *new_addr = mmap(NULL, SLAB_SIZE + sizeof(slab), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
102 slab *new_slab = new_addr;
103 new_slab->addr = (char *)new_addr + sizeof(slab);
104 temp->next = new_slab; // Set the new slab as the one following the existing slabs
105 temp->next->addr = new_slab->addr; // Set the new slab's address to the newly mmap'd address
106 temp->next->next = NULL; // Set the new slab's NEXT pointer to NULL
107 bzero(&new_slab->bm, SLAB_SIZE/M.C[ci].alloc_unit/8); // Zero-out the new slab's bitmap
108 if(temp->addr == MAP_FAILED) { // Check if mmap succeeded...
109 printf("mmap failed. Exiting...\n");
110 exit(-1);
111 }
112 printf("Allocated memory for cache %d's slab %d at address %p\n", ci, slbn, temp->next);
113 }
114 printf("Use cache %d , slab %d (allocation unit size: %d)\n", ci, slbn,M.C[ci].alloc_unit);
115 printf("Found slot %d in slab %d of cache %d\n", si % (SLAB_SIZE/M.C[ci].alloc_unit), slbn, ci);
116
117 // 3.b Slot found
118
119 if(M.C[ci].S.addr == NULL) { // Slab not allocated yet
120 M.C[ci].S.addr = mmap(NULL, SLAB_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
121 printf("Allocated memory for cache %d's slab at address %p\n", ci, M.C[ci].S.addr);
122 }
123
124 if(M.C[ci].S.addr == MAP_FAILED) {
125 perror("mmap failed\n");
126 exit(-1);
127 }
128 set_bit(&M.C[ci].S.bm[bmi], pos); // mark the bit as occupied
129
130 // 4. Return address
131
132 return M.C[ci].S.addr + si*M.C[ci].alloc_unit;
133 }
违规行似乎是line 77
。运行 GDB 会给我以下结果:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400847 in allocate_cache (size=5) at allocator.c:77
77 pos = find_zero_bit(next_slab->bm[lbmi]); // Until a free slot has been found
但是,我不明白这是怎么回事。next_slab
已正确初始化 ( line 101-111
,并且 bm 是使用 bzero ( ) 清零的位图line 107
。因此,我倾向于认为这是一个不同的问题,只是在第 107 行弹出,但我无法诊断它几天。
我也一直在检查我的逻辑,以确保我没有做任何愚蠢的事情,比如覆盖slab struct 地址,但据我所知,mmap 提供给我的范围不允许这种情况发生。
任何帮助或指示将不胜感激。
PS。如果您希望我以任何方式重新格式化代码,请告诉我。我意识到这可能有点难看。
编辑:一开始的缓存初始化是在我的init_memory()
函数中完成的。与缓存相关的行如下:
161 // Init the caches
162 for(i =0; i<9; i++) {
163 M.C[i].alloc_unit = 8<<i;
164 M.C[i].S.addr = NULL;
165 M.C[i].S.next = NULL;
166 bzero(M.C[i].S.bm, SLAB_SIZE/M.C[i].alloc_unit/8);
167 }
更新:看来我发现了错误。这是一个逻辑错误,而不是其他任何事情。我的位图数组的大小为 256,即 0..255。在 8 字节分配的情况下,位图正确设置为 256,表示最后一个空闲槽已用完,但这与我的位图定义相冲突,因为 bm[256] 是非法读取。因此,未定义的行为。我通过简单地将位图数组的大小增加 1 来解决这个问题,即int bm[((SLAB_SIZE/8)/(8*sizeof(int)))+1];
.
非常感谢 Koushik,他帮助我解决了这个问题。他建议我在几个地方添加的括号可能也为我省去了一些调试方面的麻烦。