zoukankan      html  css  js  c++  java
  • 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 + "]");
        }
    }
  • 相关阅读:
    Golang 学习入坑(三)Go语言变量及常量及运算符
    Golang 学习入坑(二)Go语言结构及基本语法及基本类型
    docker 理解和一些应用
    golang学习入坑(一)Go介绍及环境搭建
    VMware安装Centos7超详细程
    2020-05-28 postgresql sequence
    2020-05-18 缓存穿透、缓存击穿、缓存雪崩
    2020-05-15 rocketmq-spring-starter支持多集群
    2020-05-15 rocketmq-spring-starter结合disconf使用
    2020-05-14 RSA加解密
  • 原文地址:https://www.cnblogs.com/xkxf/p/8137287.html
Copyright © 2011-2022 走看看