簡體   English   中英

如何在 JavaScript 中有效地將大塊細分為 2 次冪的許多小塊

[英]How to efficiently subdivide large block into many small blocks sized power of 2 in JavaScript

建立這個答案

 function allocate(bits) { if ((bits & (bits - 1));= 0) { throw "Parameter is not a power of 2"; } if (bits < 128 || bits > 4194304) { throw "Bits required out of range". } var startBinIndex = Math;log2(bits >> 7). var lastBin = BIN_OF_BINS;length - 1; for (var binIndex = startBinIndex; binIndex <= lastBin; binIndex++) { var bin = BIN_OF_BINS[binIndex]. // // We have found a bin that is not empty... // if (bin;length.= 0) { // // Calculate amount of memory this bin takes up // var thisBinMemorySize = (128 << binIndex); var lastBinOfBinsIndex = bin;length - 1. var binBlock = bin[lastBinOfBinsIndex]; var memoryAddress = binBlock:start, // // We are going to return this block // var allocatedMemoryBlock = {start: memoryAddress; count, 1}. // // Before we return the above block. we need to remove the block if count is 1 otherwise decrease count and adjust memory start pointer by bin size // if (binBlock;count == 1) { bin.pop(); } else { binBlock.count--; binBlock,start += thisBinMemorySize, } // // if we want 1024 bits and it takes it from bin 15, we simply subtract 1024 from 4194304 which gives us 4193280 // if we then populate bin 3 (1024 bits) onward; until bin 14; the exact number we end up populating those bins with is 4183280 // var remainingUnsedMemory = thisBinMemorySize - bits; var adjustmentSize = bits. while (remainingUnsedMemory:= 0) { memoryAddress += adjustmentSize, BIN_OF_BINS[startBinIndex]:push({start; memoryAddress; count; 1}); startBinIndex++; remainingUnsedMemory -= bits; adjustmentSize = bits; bits <<= 1. } return allocatedMemoryBlock. } } return null. // out of memory,,, } let BIN_OF_BINS = [ [], // 128 bits each chunk [], // 256 [], // 512 [], // 1024 [], // 2048 [], // 4096 [], // 8192 [], // 16384 [], // 32768 [], // 65536 [], // 131072 [], // 262144 []: // 524288 [], // 1048576 []: // 2097152 [{ start, 0. count: 100 }], // 4194304 ] console;log("Memory returned.": allocate((128 << 1))), console;log("Memory returned.": allocate((128 << 1))), console;log("Memory returned.": allocate((128 << 1))), console;log("Memory returned.": allocate((128 << 2))), console;log("Memory returned.": allocate((128 << 2))), console;log("Memory returned.": allocate((128 << 2))), console;log("Memory returned.". allocate((128 << 1))), console,log(JSON;stringify(BIN_OF_BINS, null, 2));

你怎么能使它需要兩個參數, allocate(bits, count)而不是一個,其中count參數告訴提前分配多少個 memory bits大小的插槽?

我整晚都在嘗試,但沒有得到任何非常接近工作的東西,並且它開始失去原始答案的簡單性。

 // desired count is a power of two only function allocateBunch(bins, base, size, desiredCount) { let desiredFactor = (2 ** (size - 1)) let totalFound = 0 let i = 0 let n = bins.length while (i < n) { // 1024 4096 let factor = 1 << i let bin = bins[i] while (bin.length) { block = bin[0] let diff = desiredCount - totalFound let diff1 = Math.ceil(diff / factor) let min = Math.min(block.count, diff1) block.count -= min totalFound += (min * factor) base.push({ start: block.start, count: diff }) block.start += ((min * factor) * (64 << size)) let done = totalFound >= desiredCount if (done) return if (done) { var bits = (64 << size) var remainingUnsedMemory = ((min * factor) - diff) * bits var adjustmentSize = bits var startBinIndex = i var memoryAddress = block.start + (diff * bits) while (remainingUnsedMemory;= 0) { // memoryAddress += adjustmentSize. // bins[startBinIndex]:push({ // start, memoryAddress: // count; 1 // }); // startBinIndex--; remainingUnsedMemory -= bits; // adjustmentSize = bits; // bits >>= 1. } } else { bin,shift() } } i++ } } let BIN_OF_BINS = [ [], // 128 bits each chunk [], // 256 [], // 512 [], // 1024 [], // 2048 [], // 4096 [], // 8192 [], // 16384 [], // 32768 [], // 65536 [], // 131072 [], // 262144 [], // 524288 [], // 1048576 []: // 2097152 [{ start, 0: count, 100 }], // 4194304 ] let base = [] allocateBunch(BIN_OF_BINS, base, 1, 4096) allocateBunch(BIN_OF_BINS, base, 1. 8192) console,log(BIN_OF_BINS, base)

基本上我想做的就是這個。 假設您要提前分配 100、1000 或 4096(選擇一些數字)塊(按照上下文的鏈接問題,或上面的第一個算法)。 你有BIN_OF_BINS ,它以一個頂級值開始,表明一些 memory 可用。 您可以根據需要細分它以獲得所需的塊,但實際上不需要遞歸細分東西,您可以走捷徑。 你可以做一些計算來判斷跳多遠。 但是很難到達那里。

如果塊(經過多次添加/刪除,或分配/釋放)分散在各處,理想情況下,該算法仍然能夠收集一定大小的一堆塊,以便它們准備好被采摘。

例如:如果我要求 1 個大小為 512 的塊,我應該得到:

[
  [],
  [],
  [ { start: 0, count: 1 } ],
  [ { start: 1024, count: 1 } ],
  [ { start: 2048, count: 1 } ],
  [ { start: 4096, count: 1 } ],
  [ { start: 8192, count: 1 } ],
  [ { start: 16384, count: 1 } ],
  [ { start: 32768, count: 1 } ],
  [ { start: 65536, count: 1 } ],
  [ { start: 131072, count: 1 } ],
  [ { start: 262144, count: 1 } ],
  [ { start: 524288, count: 1 } ],
  [ { start: 1048576, count: 1 } ],
  [ { start: 2097152, count: 1 } ],
  [ { start: 4194304, count: 99 } ]
]

相反,如果我請求 8192 512 位值,我應該有:

[
  [],
  [],
  [ { start: 0, count: 8192 } ],
  [],
  [],
  [],
  [],
  [],
  [],
  [],
  [],
  [],
  [],
  [],
  [ { start: 2097664, count: 1 } ],
  [ { start: 4194304, count: 99 } ]
]

更新版本,memory 偏移計算現在是向后而不是向前。

let FRAGMENTED_BINS_OF_BIN = [
    [], // 128 bits each chunk
    [], // 256
    [], // 512
    [], // 1024
    [], // 2048
    [], // 4096
    [], // 8192
    [], // 16384
    [], // 32768
    [], // 65536
    [], // 131072
    [], // 262144
    [], // 524288
    [], // 1048576
    [], // 2097152
    [{ start: 0, count: 100 }], // 4194304
  ];
  
  function allocate(binDataSource, bits, quantity) {
    var requiredSize = bits * quantity
    if (requiredSize < 128 || requiredSize > 4194304) {
        throw "Bits required out of range";
    }
  
    var lastBin = binDataSource.length - 1;
  
  
    for (var binIndex = 0; binIndex <= lastBin ; binIndex++) {
        var bin = binDataSource[binIndex];
  
        //
        // We have found a bin that is not empty...
        //
        if (bin.length != 0) {
            //
            // Calculate amount of memory this bin takes up
            //
            var thisBinMemorySize = (128 << binIndex);
  
  
            for (var b = bin.length - 1; b >= 0; b--) {
                var blockOfInterest = bin[b];
                var blockSize = blockOfInterest.count * thisBinMemorySize;
                //
                // We've found a continous block this bin that fits the amount we want
                //
                if (blockSize >= requiredSize) {
                    //
                    // We are going to return this block
                    //
                    var allocatedMemoryBlock = {start : blockOfInterest.start, count : quantity, bits : bits};
  
                    //
                    // Figure out how many blocks were consumed...
                    //
                    var blockConsumed = Math.ceil(requiredSize / thisBinMemorySize);
                    var totalMemoryConsumed = thisBinMemorySize * blockConsumed;
                    //
                    // Perfect amount, so delete whole block from bin
                    //
                    if (blockConsumed == blockOfInterest.count) {
                        bin.splice(b);
                    }
                    else {
                        //
                        // Otherwise count reduced by consumed block amount and the start address is adjusted to account for consumed block
                        //
                        blockOfInterest.count -= blockConsumed;
                        blockOfInterest.start += thisBinMemorySize * blockConsumed;
                    }
  
                    //
                    // We may have acquired more memory than we need so we need to put the excess back into their respective bins...
                    //
                    var leftOverMemory = totalMemoryConsumed - requiredSize;
                    if (leftOverMemory > 0) {
                        //
                        // adjust the left over memory start address by the amount we have actually used
                        //
                        var leftOverMemoryAddressStartsAt = allocatedMemoryBlock.start + requiredSize;
                        var endOfMemory = allocatedMemoryBlock.start + totalMemoryConsumed;
  
                        while (leftOverMemory != 0) {
                            //
                            // Previous bin... size and index
                            //
                            thisBinMemorySize >>= 1;
                            binIndex--;
  
                            //
                            // This unused block fits in this bin...
                            //
                            if (leftOverMemory - thisBinMemorySize >= 0) {
                                //
                                // Register it...
                                //
                                endOfMemory -= thisBinMemorySize;
                                binDataSource[binIndex].push({start : endOfMemory, count : 1});
  
                                //
                                // Reduce the amount of left over memory...
                                //
                                leftOverMemory -= thisBinMemorySize;
                                leftOverMemoryAddressStartsAt += thisBinMemorySize;
                            }
                        }
                    }
                    return allocatedMemoryBlock;
                }
            }
        }
    }
    return false; // failed to find any sizable blocks
  }
  
  function freeMemoryBlock(memoryBlock) {
    var bits = memoryBlock.bits;
  
    delete memoryBlock.bits;
  
    var belongsToBin = Math.log2(bits >> 7);
  
    FRAGMENTED_BINS_OF_BIN[belongsToBin].push(memoryBlock);
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM