参考: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. app打包常用操作

    1.修改appId android:打开build.gradle文件 找到defaultConfig{applicationId 'ceshi'} 修改测试.android studio会提示. Gr ...

  2. 总结HTML5的学习方法大汇总

    html5学习方法之技能清单: 必须掌握基本的Web前端开收技术,其中包括:CSS.HTML.DOM.java.Ajax,jquery,Vue,jquery- mobile,zepto等,在掌握这些技 ...

  3. python自动发邮件库yagmail

    #### 一般发邮件方法 我以前在通过Python实现自动化邮件功能的时候是这样的: import smtplib from email.mime.text import MIMEText from ...

  4. C++反汇编第二讲,不同作用域下的构造和析构的识别

    C++反汇编第二讲,不同作用域下的构造和析构的识别 目录大纲: 1.全局(静态)对象的识别,(全局静态全局一样的,都是编译期间检查,所以当做全局对象看即可.) 1.1 探究本质,理解构造和析构的生成, ...

  5. mysql 双机热备注意事项

    上一篇文章已经介绍过    主从复制,   本文对主从复制只是简单描述,如对主从复制不清楚的,可以先看上一篇文章   主从复制  一:介绍 mysql版本:5.7.20 第一个主服服务器ip:192. ...

  6. ASP.NET MVC5+EF6+EasyUI 后台管理系统(88)-Excel导入和导出-主从表结构导出

    前言 前面一篇详细讲解了导入导出,本节演示混合结构的导出功能!同时提供代码下载.. 代码下载 vs2015+无数据库 先看效果图:这个一个混合的Excel,列表与自定义信息的混合! 我们的步骤大概分为 ...

  7. 怎么让普通用户使用root权限执行用户命令

    1.添加用户,首先用adduser命令添加一个普通用户,命令如下: #adduser tommy //添加一个名为tommy的用户#passwd tommy //修改密码Changing passwo ...

  8. web前端素材整理汇总

    最近一直搞前端开发,整理下前端用的一些常用素材,分享给大家 框架类 Vue:https://cn.vuejs.org/ iview:https://www.iviewui.com/ 插件类 Jquer ...

  9. 图片布局css

    对于平时项目开发中,经常要展示图片.什么水平居中显示,垂直居中显示,水平或垂直居中显示...我们的发际线就是这样往后退的. 接下来要讲的就是对于各种图片布局的css实现(这里针对的是img标签的不会使 ...

  10. canvas 从初级到XX 1# 部分非基础原生API的使用 [初级向]

    标题canvas 从初级到XX,XX是因为本文随机都可能会太监,并不会支持到入土.请慎重的往下看. 对于canvas的介绍,随处都可以找到,也就不啰嗦太多了.就直奔主题了. 先看一段代码,以及实现的效 ...