本次实验是使用java程序模拟伙伴系统的内存分配策略。
其中默认内存大小为1024KB,1KB为一个页,最小的页分配大小为8KB
默认有20个进程不同时间到达,随机申请1~200个页大小的内存空间,占用时间为随机1~10S
使用java程序模拟伙伴系统的内存分配,并且显示出每次分配和释放内存后,内存的占用情况。
buddy system简介:
buddy system内存管理,努力让内存分配与相邻内存合并能快速进行(对于普通算法来讲,合并内存相当困难),它利用的是计算机擅长处理2的幂运算。
我们创建一系列空闲块列表,每一种都是2的倍数。
举个例子,如果最小分配单元是8字节,整个内存空间有1M。我们创建8字节内存块链表,16字节内存块链表,32字节内存块链表,64,128,256,512,1k,2K, 4K, 8K, 16K, 32K, 64K, 128K, 256K, 512K 和一个1M内存块链表。
除了1M内存块链表有一个可用单元,其余链表初始为空。所有的内存分配都会向上取整到2的倍数----70K会向上取整到128K,15K会向上取整到16K,等等。
什么是Buddy
buddy system允许一个被分配块单元平均拆分成两个大小是原来一半的块单元,这两个块单元互为伙伴。块B的伙伴必须满足大小跟块B一样大,并且内存地址相邻(才可以合并)。
另一个伙伴性质是所有块单元在内存中的地址必须能被它自己的大小整除。比如16字节的块的地址都是一些16的倍数,如64字节的块的地址都是一些64的倍数,等等。
不仅如此,低地址的“伙伴”必须在一个能它“父亲块大小”整除,简单的说,来自同一个大块的两个小块才是伙伴。
分配内存示例
我们想分配70K的块空间
1.70K向上取整到2的倍数:128K
2.查询有128K空闲块吗?
3.没有,分配256K块。
a.有256K的空闲块吗?
b.没有,分配512K的块。
i.有512K空闲块吗?
ii.没有,分配1M的空闲块
i.有1M的空闲块吗?
ii.有,从1M的那个空闲链表中摘下,分配出去
iii.拆开一半挂在512k空闲链表上
iv.返回另一半512K块
c.拆开一半挂在256k空闲链表上
d.返回另一半256k块
4.将获得的256K的块拆两半,一半挂在128K空闲链表中
5.另一半128K块返回用户。
内存回收示例
当回收一个内存块,我们把它挂到对应的空闲链表上,然后查询它的伙伴是不是也在这个空闲链表上,如果是则合并他们然后挂接在对应2倍大小块所对应的空闲链表。重复该逻辑。假设我们回收刚刚分配的128K块内存
1.这个128K的块的伙伴也在128K的空闲链表上吗?
2.是的,移除它的128K伙伴块。
3.合并成256K的内存块
a.这个256K的块的伙伴也在256K空闲链表上吗?
b.是的,移除该伙伴并合并成512K的块。
c.这个512K的块的伙伴也在512K空闲链表上吗?
d.是的,移除该伙伴并合并成1M的块。
e.这个1M的块的伙伴也在1M空闲链表上吗?
f.没有,添加这个1M的块在1M的空闲链表上。
算法的优劣势分析
buddy system能很快地分配和回收内存块,但有内碎片,因为它要向上取2的幂的块大小,有空间浪费,但这是所有内存分配算法都避免不了的。linux系统使用它来分配内存页,很可能是因为内存页的大小是2的次幂。
编程实现模拟内存分配:
Buddy.java 该类是实现Buddy system的类,同时Main函数里是进行测试的代码。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by 32706 on 2016/12/14.
*/
public class Buddy {
public static int nowtime = 0;
private static final int memsize = 1024;//内存的页数
private static Character[] Memory = new Character[memsize];//总的内存空间大小 一个int表示一个页的大小为1KB
public static List<Task> task_list = new ArrayList<>();
public static List<Task> running_list = new ArrayList<>();
/**
* 存储空闲的页表,每个list对应相应的大小的页表块
**/
private static List<int[]> size1024K = new ArrayList<>();
private static List<int[]> size512K = new ArrayList<>();
private static List<int[]> size256K = new ArrayList<>();
private static List<int[]> size128K = new ArrayList<>();
private static List<int[]> size64K = new ArrayList<>();
private static List<int[]> size32K = new ArrayList<>();
private static List<int[]> size16K = new ArrayList<>();
private static List<int[]> size8K = new ArrayList<>();
private static Map<Integer, List> Mem = new HashMap<>();//存储所有空闲页的列表
public static void init_mem() {
for (int i = 0; i < Memory.length; i++) {
Memory[i] = '_';
}
int[] t = {0, memsize - 1};
size1024K.add(t);
Mem.put(1024, size1024K);
Mem.put(512, size512K);
Mem.put(256, size256K);
Mem.put(128, size128K);
Mem.put(64, size64K);
Mem.put(32, size32K);
Mem.put(16, size16K);
Mem.put(8, size8K);
}
static void refresh_memory(int begin, int end, int op)//刷新内存
{
if (op == 1)
for (int i = begin; i <= end; i++) {
Memory[i] = '@';
}
if (op == 0)