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 ...
随机推荐
- 九、Hadoop学习笔记————Hive简介
G级别或者T级别都只能用hadoop
- JAVA基础5——与String相关的系列(2)
差异点比较 String使用+直接拼接 这种情况需要分两种情况来讨论: 1. 都是确定的字符串常量之间进行的+号拼接的时候,由于在编译器就可以确定其具体值了,所以编译器在编译期的时候就会把这些常量拼接 ...
- 匿名HTTP透明HTTP高匿HTTP区别
透明代理的意思是客户端根本不需要知道有代理服务器的存在,但是它传送的仍然是真实的IP.你要想隐藏的话,不要用这个. 普通匿名代理能隐藏客户机的真实IP,但会改变我们的请求信息,服务器端有可能会认为我们 ...
- php中foreach中使用&的办法
刚开始在使用foreach时候一直不理解为什么要使用& 后来发现在给一个数组里面添加数据时候很好用 <?phpheader("Content-Type:text/html;ch ...
- C语言结构体1.1
结构体组成 struct 结构体名: 类型名 成员名: 建立结构体 结构体名 类型名 { 成员: }: 建立一个关于学生信息的结构体(名字,年龄,性别,学号,成绩): 结构体定义 //结构体声明 s ...
- poj 3111 K Best 最大化平均值 二分思想
poj 3111 K Best 最大化平均值 二分思想 题目链接: http://poj.org/problem?id=3111 思路: 挑战程序竞赛书上讲的很好,下面的解释也基本来源于此书 设定条件 ...
- codeforces 893D Credit Card 贪心 思维
codeforces 893D Credit Card 题目大意: 有一张信用卡可以使用,每天白天都可以去给卡充钱.到了晚上,进入银行对卡的操作时间,操作有三种: 1.\(a_i>0\) 银行会 ...
- linux API函数大全
获取当前执行路径:getcwd1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一个网络资源的连接 WNetAdd ...
- 如何使用 Secret?- 每天5分钟玩转 Docker 容器技术(108)
我们经常要向容器传递敏感信息,最常见的莫过于密码了.比如: docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql 在启动 MySQL 容器时我 ...
- 》》ajax加蒙版
在与后台交互时,用时过长.禁止页面操作等,有提示,增强页面体验: $.ajax({ type:'POST',url:url,data:obj,dataType:'json',beforeSend: f ...