参考:https://labrick.cc/2015/10/12/buddy-system-algorithm/

代码过烂 不宜参考。

output:

[operating.entity.Heap@4554617c, 1048576]
**************begin mallocing memory*****************
heap.myMalloc(16), 分割 16 次
[operating.entity.Heap@4554617c, 1048560]
heap.myMalloc(32), 分割 0 次
[operating.entity.Heap@4554617c, 1048528]
heap.myMalloc(48), 分割 0 次
[operating.entity.Heap@4554617c, 1048464]
heap.myMalloc(64), 分割 1 次
[operating.entity.Heap@4554617c, 1048400]
heap.myMalloc(80), 分割 1 次
[operating.entity.Heap@4554617c, 1048272]
**************begin freeing memory*****************
heap.myFree(32), 合并0次
[operating.entity.Heap@4554617c, 1048304]
heap.myFree(128), 合并1次
[operating.entity.Heap@4554617c, 1048368]
heap.myFree(0), 合并2次
[operating.entity.Heap@4554617c, 1048384]
heap.myFree(64), 合并2次
[operating.entity.Heap@4554617c, 1048448]
heap.myFree(256), 合并13次
[operating.entity.Heap@4554617c, 1048576]

code:

package operating.test;

import operating.entity.Heap;

public class HeapTest {

    public static void main(String[] args) {
Heap heap = new Heap();
heap.printList(); System.out.println("**************begin mallocing memory*****************");
int ptr16 = heap.myMalloc(16);
int ptr32 = heap.myMalloc(32);
int ptr48 = heap.myMalloc(48);
int ptr64 = heap.myMalloc(64);
int ptr80 = heap.myMalloc(80); System.out.println("**************begin freeing memory*****************");
heap.myFree(ptr32);
heap.myFree(ptr64);
heap.myFree(ptr16);
heap.myFree(ptr48);
heap.myFree(ptr80);
}
}

/

package operating.entity;

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList; public class Heap {
/**
* 堆空间heap初始大小
*/
private static final int HEAP_SIZE = 1024*1024;
/**
* 空闲块切割后若剩余不超过RESIDUE,则不进行切割
*/
private static final int RESIDUE = 8;
/**
* 用一个int数组来模拟堆
*/
private int[] memory;
/**
* 用于管理内存的分配状态,采用伙伴系统
*/
private HashMap<Integer, LinkedList<Integer>> blockManager = new HashMap<>(); public Heap() {
memory = new int[HEAP_SIZE];
Arrays.fill(memory, 0); LinkedList<Integer> initBlock = new LinkedList<>(); // 创建可存放最大块 1024*1024 的链表
initBlock.add(0); // 添加一个可用的块,起始地址为 0
blockManager.put(HEAP_SIZE, initBlock); // 将链表添加到映射中 (1024*1024,链表(只含有一个块))
} /**
* 计算块大小 2^i,使得 2^(i-1) < n <= 2^i
* @param requestSize
* @return
*/
private int getBlockSize(int requestSize) {
if (requestSize <= RESIDUE) return RESIDUE; // 如果所请求的块小于最小可分割块则直接返回最小可分割块大小 int i = 4;
while (requestSize > Math.pow(2, i)) {
++i;
}
return (int) Math.pow(2, i);
} /**
* 查找可用的块
* @param blockSize
* @return
*/
private int searchAvailable(int blockSize) {
LinkedList<Integer> blocks = blockManager.get(blockSize);
if (blocks != null) { // 如果恰好有该大小的内存块
for (Integer x : blocks) {
if (memory[x] != 1) { // 并且还没被使用
return x;
}
}
}
return -1;
} /**
* 分割块: 2^i 转变为两个 2^(i-1)
* @param address
* @param size
*/
private void parting(Integer address, int size) {
LinkedList<Integer> bigBlocks = blockManager.get(size); // 取得 size 大小的块
bigBlocks.remove(address);
LinkedList<Integer> smallBlocks = blockManager.get(size/2);
if (smallBlocks == null) {
smallBlocks = new LinkedList<>();
blockManager.put(size/2, smallBlocks);
}
smallBlocks.add(address);
smallBlocks.add(address + size/2);
} /**
* 合并
* @param address
* @param buddyAddress
* @param size
*/
private void merge(Integer address, Integer buddyAddress, int size) {
LinkedList<Integer> smallBlocks = blockManager.get(size);
if (smallBlocks == null) return;
smallBlocks.remove(address);
smallBlocks.remove(buddyAddress);
LinkedList<Integer> bigBlocks = blockManager.get(size*2);
bigBlocks.add(address < buddyAddress ? address : buddyAddress);
} /**
* 通过地址得到相应的块大小
* @param address
* @return
*/
private int getSize(int address) {
for (Integer size : blockManager.keySet()) {
LinkedList<Integer> blocks = blockManager.get(size);
for (Integer x : blocks) {
if (x == address) return size;
}
}
return 0;
} /**
* 分配内存
* @param size 请求的内存大小
* @return 分配内存的起始地址
*/
public int myMalloc(int size) {
int count = 0; // 计算分割次数
// 计算所需要的块的大小
int requestSize = getBlockSize(size);
// 1- 如果恰好有该大小的块,直接分配并返回
int address = searchAvailable(requestSize);
if (address != -1) {
memory[address] = 1;
System.out.println("heap.myMalloc("+ size + ")," + " 分割 " + count + " 次");
this.printList();
return address;
} // 2- 如果没有就分割,逐级向上找可以分割的块
int tempSize = requestSize;
while (address == -1 && tempSize <= HEAP_SIZE) {
// System.out.println("正在搜索 " + tempSize + "大小的块。");
address = searchAvailable(tempSize*=2);
}
// System.out.println("找到了可分割的块。");
if (tempSize > HEAP_SIZE) {
System.out.println("没有足够的空间!");
return -1;
} else { // 分割出需要的块
while (searchAvailable(requestSize) == -1) {
// System.out.println("正在对起始地址为" + address + "大小为" + tempSize + "的块进行分割");
parting(address, tempSize);
++ count;
tempSize = tempSize/2;
}
} // 3- 重复 1
address = searchAvailable(requestSize);
memory[address] = 1;
System.out.println("heap.myMalloc("+ size + ")," + " 分割 " + count + " 次");
this.printList();
return address;
} /**
* 释放起始地址为 address 的内存
* @param address
*/
public void myFree(int address) {
int count = 0; // 计算合并次数
int originAddress = address;
memory[address] = 0;
while (true) {
int size = getSize(address);
// 计算伙伴块的地址
int buddyAddress = -1;
if (size != 0 && address % (size*2) == size) {
buddyAddress = address - size;
} else {
buddyAddress = address + size;
}
if (buddyAddress >=0 && buddyAddress < HEAP_SIZE && memory[buddyAddress] != 1) { // 如果伙伴块没被使用就合并
merge(address, buddyAddress, size);
++count;
} else {
break;
}
if (buddyAddress < address) {
int temp = address;
address = buddyAddress;
buddyAddress = temp;
}
}
System.out.println("heap.myFree("+ originAddress + ")," + " 合并" + count + "次");
this.printList();
} public void printList() {
int rest = HEAP_SIZE;
for (Integer size : blockManager.keySet()) {
LinkedList<Integer> blocks = blockManager.get(size);
for (Integer x : blocks) {
if (memory[x] == 1) {
rest -= size;
}
}
}
// 仅仅是模拟,java 无法真正获取对象内存地址
System.out.println("[" + this + ", " + rest + "]");
}
}

Java伙伴系统(模拟)的更多相关文章

  1. Java爬虫模拟登录——不给我毛概二的H某大学

    你的账号访问太频繁,请一分钟之后再试! 从大一开始 就用脚本在刷课 在专业课踢的只剩下一门C#的情况下 活活刷到一周的课 大二开始教务系统多了一个非常**的操作 退课池 and 访问频繁缓冲 难道,我 ...

  2. Java实现模拟登录新浪微博

    毕设题目要使用到新浪微博数据,所以要爬取新浪微博的数据.一般而言,新浪微博的爬虫有两种模式:新浪官方API和模拟登录新浪微博.两种方法的异同点和适用情况就无须赘述了.前辈的文章已经非常多了.写这篇文章 ...

  3. java模拟表单上传文件,java通过模拟post方式提交表单实现图片上传功能实例

    java模拟表单上传文件,java通过模拟post方式提交表单实现图片上传功能实例HttpClient 测试类,提供get post方法实例 package com.zdz.httpclient; i ...

  4. java多线程模拟生产者消费者问题,公司面试常常问的题。。。

    package com.cn.test3; //java多线程模拟生产者消费者问题 //ProducerConsumer是主类,Producer生产者,Consumer消费者,Product产品 // ...

  5. Java&Selenium 模拟键盘方法封装

    Java&Selenium 模拟键盘方法封装 package util; import java.awt.AWTException; import java.awt.Robot; import ...

  6. Java&Selenium 模拟鼠标方法封装

    Java&Selenium 模拟鼠标方法封装 package util; import org.openqa.selenium.By; import org.openqa.selenium.W ...

  7. Java 伙伴系统(模拟)

    参考:https://labrick.cc/2015/10/12/buddy-system-algorithm/ 代码过烂 不宜参考. output: [operating.entity.Heap@4 ...

  8. java多线程模拟停车系统

    import java.util.Random; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent ...

  9. java代码模拟先入先出,fifo

    最近在做一个先入先出的出库.琢磨了一下,写了一个简单的java代码测试: public static void main(String[] args) { LinkedList q = new Lin ...

随机推荐

  1. 使用js里面的迭代器filter实现数组去重

    实现数组去重的方法很多,最原始的方法是一个值一个值的去遍历,写到空数组里面: let r=[],arr = ['a', 'b', 'c', 'a']; for(var i=0,len=arr.leng ...

  2. OOXML,XLSX分析

    07以上的xlsx是使用了OOXML和zip,将后缀修改为.zip,就可以看到文件,主要分析xl目录下的文件,如图: 主要数据文件在xl目录下面 styles.xml里面存放着excel的样式数据 很 ...

  3. height:calc(100% - 40px)

    在移动端开发的过程中,常常会遇到头部高度是40px,而内容页是除去头部,占满视窗的整个高度,有时候是用js来处理,现在用css的calc是非常方便的: .container{ height: calc ...

  4. ios开发-获取手机相关信息

    今天在做客户端的时候,里面有个意见反馈功能. 调用系统带的邮件功能,发送邮件到指定邮箱. 然后我就想,应该在邮件正文部分添加手机相关内容,比如型号,版本,应用程序的版本等等,这样不仅使用者方便,开发者 ...

  5. js 模拟 select 的 click 事件

    法一. 你可以直接通过修改 select 的 size 属性来实现,但是这样比较丑,很明显:原来: 修改 size: 跟原生比丑在两点: 位置上移了 滚动条出现了 法二. 比较好的实现,就是通过 js ...

  6. Cookies Client Identification

    HTTP The Definitive Guide Cookies are the best current way to identify users and allow persistent se ...

  7. MySQL中的表级锁

    数据的锁主要用来保证数据的一致性,数据库的锁从锁定的粒度上可以分为表级锁,行级锁和页级锁. MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制,比如MyISAM和MEMORY存 ...

  8. Swift学习——Swift基础具体解释(一)

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/zhenyu5211314/article/details/34807025 注:由于基础部分在Swi ...

  9. DIV+CSS如何让文字垂直居中?

    在说到这个问题的时候,也许有人会问CSS中不是有vertical-align属性来设置垂直居中的吗?即使是某些浏览器不支持我只需做少许的CSS Hack技术就可以啊!所以在这里我还要啰嗦两句,CSS中 ...

  10. (转)理解POST和PUT的区别,顺便提下RESTful

    这两个方法咋一看都可以更新资源,但是有本质区别的 具体定义可以百度,我这里就不贴了,光说我自己的理解 首先解释幂等,幂等是数学的一个用语,对于单个输入或者无输入的运算方法,如果每次都是同样的结果,则称 ...