JavaScript实现Linux内存管理伙伴算法

操作系统课程设计

要求

Linux中内存分配的伙伴堆算法模拟。
(1)模拟内存实始情况。
(2)实现Buddy heap算法。
(3)通过键盘输入随机产生的申请和释放操作。
(4)每次申请或释放都显示实时的内存分配的对比图。


实现结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


伙伴算法:

Linux把空闲的页面按照页块大小分组进行管理。用数组管理各个空闲页块组。当进程提出存储请求时。系统按照Buddy算法。根据请求的 页面数在free_area口对应的空闲页块组中搜索。linux并不是按 照要求的页块的数目去进行分配.而是将大于、等于这个数目的 最小2n个页块分配出去。比如,要求3个页块。就分配2-2=4块;要求16个页块,就分配24=16块.如此等等。因此,系统总是按 照进程所需连续存储块的申请数量。到空闲区队列free 中 能够满足要求的最小空闲区队列里查找。当队列不空时,就把第一个空闲区分配出去。如果该队列为空.那么就继续查找下面的队列(其空闲区的尺寸为上一个队列的2倍)。当它里面有空闲区时,就把该空闲区一分为二:一个分配出去给进程使用;余下的一半.排到它上面的空闲区队列中去。

在内存页面释放时。系统将做为空闲页面看待。然后检查是否存在与这些页面相邻的其它空闲页块,若存在,则合为一 个连续的空闲区按Buddy算法重新分组。


利用JavaScript的对象数据类型和数组来存储相应的内容。
// 空闲块
let free_area = [
{
index: 0,
size: 1024
}
]

// 当前内存使用状况
let ram = [
{
state: false,
size: 1024
}
]
// 剩余空间总和
let free_ram = 1024;
其中free_area表示空闲块数组,数组中的每一个对象表示空闲块信息,index对应当前内存ram数组中空闲块的分块的下标,size表示该空闲块大小。
其中ram表示内存使用状态数组,数组中的每一个对象表示分块,state表示该块是否被使用,state为true表示已使用,反之为未使用。
其中free_ram表示当前未使用内存的大小。
后端到前端的渲染均依靠维护这三个变量。


主要算法代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
let free_area = [
{
index: 0,
size: 1024
}
]

// 当前内存使用状况
let ram = [
{
state: false,
size: 1024
}
]
// 剩余空间总和
let free_ram = 1024;




// 快速幂
var pow = function (x, n) {
let ans = 1;
for (let i = 0; i < n; i++) {
ans *= x;
}
return ans;
}
// console.log(pow(2, 10))
// 找到申请内存大小的二次幂
var findlistnum = function (size) {
for (var i = 0; i <= 10; i++) {
if (size > pow(2, i) && size < pow(2, i + 1)) {
return i + 1;
} else if (size == pow(2, i)) {
// console.log(i)
return i;
}
}
return false;
}
// 删除指定下标的数组元素并返回新数组
var deleteArrElement = function (index, arr) {
let newarr = {
deleteele: arr[index],
arr: arr
}
for (let i = index; i < arr.length; i++) {
arr[i] = arr[i + 1];
}
arr.length--;
newarr.arr = arr;

return newarr;
}
// 查找数组里面某对象的值是否是要找的值
var indexOfArrObj = function (value, arr) {
for (let i = 0; i < arr.length; i++) {
if (arr[i].size === value) {
return i;
}
}
return -1;
}
// 分配内存
// 参数为二次幂i,返回值为新的内存状态,空闲块状态,空闲内存大小;
var allocation = function (powi) {
// if(powi)
console.log(powi)
if (powi < 6) {
powi = 6;
}
let nowstate = {
ram: [],
free_area: [],
free_ram: 0
}
let blocksize = pow(2, powi)
// console.log(free_area)
if (free_area.length == 0) {
// 改成返回错误代码
return false;
} else if (free_area[0].size == 1024) {
let ramsize = 1024;
ram.pop()
free_area.pop()
for (let i = 10 - powi; i > 0; i--) {
ramsize = ramsize / 2;
let obj = {
index: i,
size: ramsize
}
// console.log(ramsize)
free_area.unshift(obj);
let tempusedobj = {
state: false,
size: ramsize
}
ram.unshift(tempusedobj)
}
let usedpbj = {
state: true,
size: ramsize
}
ram.unshift(usedpbj)
free_ram -= ramsize;

nowstate.ram = ram;
nowstate.free_area = free_area;
nowstate.free_ram = free_ram;
// console.log('allocation ans 1' + JSON.stringify(nowstate))
return nowstate;
} else {
if (indexOfArrObj(blocksize, free_area) != -1) {
let i = indexOfArrObj(blocksize, free_area);
// console.log(i)
// free_area.index不变
let newfreeare = deleteArrElement(i, free_area);
free_area = newfreeare.arr;
// console.log(free_area)
let ramindex = newfreeare.deleteele.index
ram[ramindex].state = true;
free_ram -= newfreeare.deleteele.size;

nowstate.ram = ram;
nowstate.free_area = free_area;
nowstate.free_ram = free_ram;
// console.log('allocation ans 2' + JSON.stringify(nowstate))
return nowstate;
} else {
let findupsize = blocksize;
for (let i = 0; pow(2, i) * blocksize <= free_area[free_area.length - 1].size; i++) {
findupsize *= 2;
// console.log(findupsize)
if (indexOfArrObj(findupsize, free_area) != -1) {

let nowindex = indexOfArrObj(findupsize, free_area);
console.log(nowindex)//0
let ramindex = free_area[nowindex].index;//4
//5
// let sliceindex=ram.length-1-ramindex;//0
// ram.pop();
ram.splice(ramindex, 1)
let times = 0;
console.log(free_area[nowindex])
for (let k = nowindex; free_area[nowindex].size > blocksize; k++) {
times++;
free_area[nowindex].size /= 2;
var obj = { ...free_area[nowindex] }
let usedobj = {
state: false,
size: free_area[nowindex].size
}
free_area.unshift(obj)


console.log(usedobj)
ram.splice(ramindex, 0, usedobj)

}
free_area.splice(0, 1);
let tempobj = {
state: true,
size: free_area[nowindex].size
}
ram.splice(ramindex, 0, tempobj)
// console.log(ramindex)
// ram[ramindex].state = true;


console.log(times)
if (times < 2) {
// console.log(222)
for (let k = nowindex; k < free_area.length; k++) {
free_area[k].index++;
}
} else if (times >= 2) {
// console.log(111)
let freenowindex = free_area[nowindex].index;
for (let k = nowindex; k < free_area.length; k++) {
if (free_area[k].index == freenowindex) {
free_area[k].index = freenowindex + (k - nowindex) + 1;
} else {
free_area[k].index += times;
}
}
}
console.log(free_area)

free_ram -= free_area[nowindex].size;


nowstate.ram = ram;
nowstate.free_area = free_area;
nowstate.free_ram = free_ram;

return nowstate;
}
}

return false;
}
}
}
// 找寻对应的空闲块,如果找到并分配成功返回true;分配失败返回false;
// 参数:申请内存大小
var findFreeBlock = function (size) {
let blockpow = findlistnum(size);
console.log(blockpow)
if (blockpow === false) {
return false;
}
let newstate = $.parseJSON(JSON.stringify(allocation(blockpow)));
// console.log(newstate)
console.log(newstate)
if (newstate == false) {
// console.log('findFreeBlock ans 1')
return false;
}
else {
// console.log(newstate.ram)
ram = newstate.ram;
free_area = newstate.free_area;
free_ram = newstate.free_ram;
// console.log('findFreeBlock ans 2')
return true;
}
}

// 渲染内存界面;
var renderAllocation = function () {
if (free_ram == 1024) {
ram = [{
size: 1024,
state: false
}]
free_area = [{
index: 0,
size: 1024
}]
}
let sum = 1024
// console.log(bcg.innerHTML)
let html = ''
for (let i = 0; i < ram.length; i++) {
if (ram[i].state == true) {
let width = ram[i].size / sum * 100 + '%';
var useddiv = `<div class="used block ` + `kb` + ram[i].size + `" style="width:` + width + ` ">` + ram[i].size + `KB</div>`
html += useddiv
} else {
let freewidth = ram[i].size / sum * 100 + '%';
var freediv = `<div class="free block" style="width: ` + freewidth + `">` + ram[i].size + `KB` + `</div>`;
html += freediv;
}
}
bcg.innerHTML = html;



// $('.bcg').append(useddiv);


// console.log('renderAllocation ans 1')
}
// 格式化时间
var formatDateTime = function (date) {
// var y = date.getFullYear();
// var m = date.getMonth() + 1;
// m = m < 10 ? ('0' + m) : m;
// var d = date.getDate();
// d = d < 10 ? ('0' + d) : d;
var h = date.getHours();
h = h < 10 ? ('0' + h) : h;
var minute = date.getMinutes();
minute = minute < 10 ? ('0' + minute) : minute;
var second = date.getSeconds();
second = second < 10 ? ('0' + second) : second;
return h + ':' + minute + ':' + second;
};
//申请内存 参数:申请内存大小
var applicationram = function (size) {

let isAllocationOk = findFreeBlock(size);
// console.log(isAllocationOk)
if (!isAllocationOk) {
// console.log('applicationram ans 1')
window.alert('分配失败');
let messagewrap = document.createElement('div');
let messagediv = document.createElement('span');
messagewrap.classList.add('message-wrap');
messagediv.classList.add('message-text');
messagediv.classList.add('fail');
messagediv.classList.add('applicationtext')
let date = new Date();
var datestr = formatDateTime(date);
messagediv.innerHTML = datestr + `分配内存` + size + `KB 失败!`;
messagewrap.appendChild(messagediv);

let leftwrap = document.getElementsByClassName('left-wrap')[0];
leftwrap.appendChild(messagewrap);
setTimeout(function (param) {
messagewrap.classList.add('active')
}, 1);
setTimeout(function () {
messagewrap.classList.add('disappear');
}, 5000);
setTimeout(function(){
messagewrap.style.display='none'
},10000);
renderAllocation()
} else {
// console.log('applicationram ans 2')
let messagewrap = document.createElement('div');
let messagediv = document.createElement('span');
messagewrap.classList.add('message-wrap');
messagediv.classList.add('message-text');
messagediv.classList.add('applicationtext')
let date = new Date();
var datestr = formatDateTime(date);
messagediv.innerHTML = datestr + ` 成功分配内存` + size + `KB !`;
messagewrap.appendChild(messagediv);

let leftwrap = document.getElementsByClassName('left-wrap')[0];
leftwrap.appendChild(messagewrap);
setTimeout(function (param) {
messagewrap.classList.add('active')
}, 1);
setTimeout(function () {
messagewrap.classList.add('disappear');
}, 5000);
setTimeout(function(){
messagewrap.style.display='none'
},10000);
renderAllocation()

}
}
//确定分配内存
var buddyheap = function (state) {

if (state == true) {
let applicationsize = document.getElementsByClassName('input')[0].value;
// 申请内存
applicationram(applicationsize)
}

}
// applicationram(70)
applicationbtn.addEventListener('click', function () {
state = true;
// console.log(state)
buddyheap(state);

})

// 给已申请成功的内存块加监听事件
var usedramaddevent = function () {
return new Promise(function (resolve, reject) {
for (let i = 0; i < blockram.length; i++) {
let index = i;
blockram[i].addEventListener('click', function () {
console.log(index)
var that = this
if (ram[index].state == true) {
if (confirm('release this block?')) {
resolve(index)
} else {
resolve(false)
}
}

})
}
});
}
// 释放内存 参数:释放内存大小,释放内存块在内存中的下标
var releasram = function (size, index) {
// console.log(ram)
let flag = true;
let k = 0;
let obj = {
index: index,
size: size
}
free_area.unshift(obj)
free_area.sort(function (a, b) {
return a.index - b.index
})
console.log(free_area)
if (free_area.length == 1) {
let ramindex = free_area[k].index;
ram[ramindex].state=false;
console.log(ramindex)
} else {
while (flag == true) {
console.log(size)
if (k == 0) {
flag = false;
}
// 当从头到尾没有伙伴内存的时候,flag=false
if (k >= free_area.length - 1) {
k = (k % free_area.length) - 1;
}

if ((free_area[k].index - free_area[k + 1].index == -1) && (free_area[k].size == free_area[k + 1].size)) {
console.log(444)
let ramindex = free_area[k].index;
ram[ramindex].size *= 2;
ram[ramindex].state = false;

ram.splice(ramindex + 1, 1);
free_area[k].size *= 2;
free_area.splice(k + 1, 1);
for (let i = k + 1; i < free_area.length; i++) {
free_area[i].index--;
}
flag = false;
} else {
flag = true;
k++;
}

if ((k == free_area.length - 1 && flag == true) || free_area.length == 1) {
console.log(999)
flag=false;
}else{
flag=true;
}

}
}
console.log(free_area)
let s = 0;
for (let i = 0; i < free_area.length; i++) {
s += free_area[i].size;
}
free_ram = s;
// console.log(ram)
}