Java伙伴系统(模拟)
参考: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伙伴系统(模拟)的更多相关文章
- Java爬虫模拟登录——不给我毛概二的H某大学
你的账号访问太频繁,请一分钟之后再试! 从大一开始 就用脚本在刷课 在专业课踢的只剩下一门C#的情况下 活活刷到一周的课 大二开始教务系统多了一个非常**的操作 退课池 and 访问频繁缓冲 难道,我 ...
- Java实现模拟登录新浪微博
毕设题目要使用到新浪微博数据,所以要爬取新浪微博的数据.一般而言,新浪微博的爬虫有两种模式:新浪官方API和模拟登录新浪微博.两种方法的异同点和适用情况就无须赘述了.前辈的文章已经非常多了.写这篇文章 ...
- java模拟表单上传文件,java通过模拟post方式提交表单实现图片上传功能实例
java模拟表单上传文件,java通过模拟post方式提交表单实现图片上传功能实例HttpClient 测试类,提供get post方法实例 package com.zdz.httpclient; i ...
- java多线程模拟生产者消费者问题,公司面试常常问的题。。。
package com.cn.test3; //java多线程模拟生产者消费者问题 //ProducerConsumer是主类,Producer生产者,Consumer消费者,Product产品 // ...
- Java&Selenium 模拟键盘方法封装
Java&Selenium 模拟键盘方法封装 package util; import java.awt.AWTException; import java.awt.Robot; import ...
- Java&Selenium 模拟鼠标方法封装
Java&Selenium 模拟鼠标方法封装 package util; import org.openqa.selenium.By; import org.openqa.selenium.W ...
- Java 伙伴系统(模拟)
参考:https://labrick.cc/2015/10/12/buddy-system-algorithm/ 代码过烂 不宜参考. output: [operating.entity.Heap@4 ...
- java多线程模拟停车系统
import java.util.Random; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent ...
- java代码模拟先入先出,fifo
最近在做一个先入先出的出库.琢磨了一下,写了一个简单的java代码测试: public static void main(String[] args) { LinkedList q = new Lin ...
随机推荐
- Spring源码从开始到放弃(一)
参考<Spring技术内幕>分析. github上面有spring的源码(https://github.com/spring-projects/spring-framework) spri ...
- [SharePoint 2010] 如何在小組網站內頁面上撥放影片或是音效檔
在SharePoint 2010中, 我們可以像是Youtube一樣在網頁上撥放影片或是音效檔案. 影片或音效是採取串流的方式來撥放. 也就是說我們不需要把整個檔案都下載回來才開始撥放. 點選沒多久我 ...
- PAT 甲级 1021 Deepest Root (并查集,树的遍历)
1021. Deepest Root (25) 时间限制 1500 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A graph ...
- Linux 常用资源
kernel:ftp://kernel.orgcnkernel:http://www.cnkernel.orgoldlinux:http://www.oldlinux.orgminix3:http:/ ...
- Graphite grafana
Graphite http://graphiteapp.org/ Graphite is an enterprise-ready monitoring tool that runs equally w ...
- order meeting room - 离散度30min
w <meta charset="UTF-8"> <?php include('conn.php'); include('w_fun.php'); include ...
- flask中current_app._get_current_object()与current_app有什么区别?
https://segmentfault.com/q/1010000005865632/a-1020000005865704
- 剑指Offer——把二叉树打印成多行
题目描述: 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 分析: 二叉树的层次遍历,利用队列. 代码: /* struct TreeNode { int val; struct T ...
- 为golang程序使用pprof远程查看httpserver运行堆栈,cpu耗时等信息
pprof是个神马玩意儿? pprof - manual page for pprof (part of gperftools) 是gperftools工具的一部分 gperftools又是啥? Th ...
- 20.Bulk Write Operations-官方文档摘录
1.有序操作列表将会串行执行,但如果在一个写操作过程出现异常错误,则不会处理剩余的任何写操作 2.无序操作列表将会并发执行,如果在一个写操作过程出现异常错误,则不影响,继续执行(并发无序) 3.对比无 ...