首页 > 代码库 > [编织消息框架][netty源码分析]14 PoolChunk 的 PoolSubpage

[编织消息框架][netty源码分析]14 PoolChunk 的 PoolSubpage

 

final class PoolSubpage<T> implements PoolSubpageMetric {    //该page分配的chunk    final PoolChunk<T> chunk;    //内存使用记录    private final long[] bitmap;    //该page是否已释放    boolean doNotDestroy;        //该page在chunk中的id,通过区段计算偏移    private final int memoryMapIdx;    //该page在chunk.memory的偏移量    private final int runOffset;    //page大小     private final int pageSize;    //page切分后每一段的大小 最少等于16通过 PoolArena#normalizeCapacity方法计算    int elemSize;    //page包含的段数量    private int maxNumElems;    private int bitmapLength;    //下一个可用的位置,用于优化findNextAvail计算    private int nextAvail;    //可用的段数量    private int numAvail;        //每个分页大小 pageSize = 8192(8k)    //分页里每个单元大小 elemSize最少等于16 通过 PoolArena#normalizeCapacity方法计算    void init(PoolSubpage<T> head, int elemSize) {        doNotDestroy = true;        this.elemSize = elemSize;        if (elemSize != 0) {            maxNumElems = numAvail = pageSize / elemSize;            nextAvail = 0;                        //所有数据除以64分段 >>>6 等于 /(6*6)            bitmapLength = maxNumElems >>> 6;            //最后边界加1处理            if ((maxNumElems & 63) != 0) {                bitmapLength ++;            }            //初始化bitmap清零            for (int i = 0; i < bitmapLength; i ++) {                bitmap[i] = 0;            }        }    }        long allocate() {        if (elemSize == 0) {            return toHandle(0);        }        if (numAvail == 0 || !doNotDestroy) {            return -1;        }        final int bitmapIdx = getNextAvail();        //计算出在那一段        int q = bitmapIdx >>> 6;                //等于(运算值+1)的倍数,那么结果就为0。如bits & 63 当bits等于64的倍数时结果为0,否则取min(bits,64) 或 bits/64 余数        //这里意思是取当前段的所有状态        int r = bitmapIdx & 63;        //设置相应位置状态        bitmap[q] |= 1L << r;        //没有可以执行回收        if (-- numAvail == 0) {            removeFromPool();        }        return toHandle(bitmapIdx);    }        //这里做了优化,当执行free时会重新计算nextAvail,这时可直接返回    private int getNextAvail() {        int nextAvail = this.nextAvail;        if (nextAvail >= 0) {            this.nextAvail = -1;            return nextAvail;        }        return findNextAvail();    }    private int findNextAvail() {        final long[] bitmap = this.bitmap;        final int bitmapLength = this.bitmapLength;        for (int i = 0; i < bitmapLength; i ++) {            long bits = bitmap[i];            //取反不等于0说明还有空位可以使用            if (~bits != 0) {                return findNextAvail0(i, bits);            }        }        return -1;    }    private int findNextAvail0(int i, long bits) {        final int maxNumElems = this.maxNumElems;        //算出在那一段基础值        final int baseVal = i << 6;        //这里用到 >>> 即每位检查是否占用,如果没有占到计算实际id返回 val = baseVal | j        for (int j = 0; j < 64; j ++) {            // bits & 1 转换成 bits & b01 该第一位二进制没有状态说明该位置没使用            if ((bits & 1) == 0) {                //算出当前段第几位                int val = baseVal | j;                //少于maxNumElems直接返回,否则返回-1                if (val < maxNumElems) {                    return val;                } else {                    break;                }            }                        //>>>= 右移(向低位移动),左边空出位(高位)以0填充            //>>>1降低一位            bits >>>= 1;        }        return -1;    }        private long toHandle(int bitmapIdx) {        return 0x4000000000000000L | (long) bitmapIdx << 32 | memoryMapIdx;    }        //返回true已在使用,返回false已释放    boolean free(PoolSubpage<T> head, int bitmapIdx) {        if (elemSize == 0) {            return true;        }        int q = bitmapIdx >>> 6;        int r = bitmapIdx & 63;        bitmap[q] ^= 1L << r;        nextAvail = bitmapIdx;        if (numAvail ++ == 0) {            addToPool(head);            return true;        }        if (numAvail != maxNumElems) {            return true;        } else {            // Subpage not in use (numAvail == maxNumElems)            if (prev == next) {                // Do not remove if this subpage is the only one left in the pool.                //subpage是pool唯一的,不能删除                return true;            }            //设置删除记录            doNotDestroy = false;            removeFromPool();            return false;        }    }}

 

通过PoolSubpage构造时打断点追踪如何分配pageSize,elemSize

PoolArena normalizeCapacity方法分配 elemSize

static int normalizeCapacity(int reqCapacity) {        // 大等于512时 双倍增加        if ((reqCapacity & -512) != 0) {            // 这里为什么不用 normalizedCapacity<<1 直接加倍,有可能normalizedCapacity刚好是512倍数            int normalizedCapacity = reqCapacity;            // 减一是避免双倍自增            normalizedCapacity--;            // 将低四位的二进制都设置为1,一个int是32位            // 注释掉代码是优化过的,逻辑用for简明示例            // normalizedCapacity |= normalizedCapacity >>> 1;            // normalizedCapacity |= normalizedCapacity >>> 2;            // normalizedCapacity |= normalizedCapacity >>> 4;            // normalizedCapacity |= normalizedCapacity >>> 8;            // normalizedCapacity |= normalizedCapacity >>> 16;            for (int i = 1; i <= 16; i++) {            normalizedCapacity |= reqCapacity >>> i;            }            // 最后要加回1            normalizedCapacity++;            // 少于0去掉最高位1即可变正数            if (normalizedCapacity < 0) {            normalizedCapacity >>>= 1;            }            return normalizedCapacity;        }        // 少于512情况        // 刚好16倍数直接返回        if ((reqCapacity & 15) == 0) {            return reqCapacity;        }        // &~15 相当于 &-16        // 如果少于16结果为0,否则大于16取16的倍数        return (reqCapacity & ~15) + 16;    }

 

我们使用简化的方式来实现PoolSubpage bitmap处理逻辑,方便读者明白如何用long来做储存,应用大量的 & |  >>> 等运算

public class TestPoolSubpage {    private static int pageSize = 1024*8;    private static int maxNumElems = pageSize / 16;    private static int bitmapLength = maxNumElems >> 6;    static{     if ((maxNumElems & 63) != 0) {             bitmapLength ++;         }     }    private static List<Boolean>[] bitmap = new ArrayList[bitmapLength];    public static void main(String[] args) {        for (int i = 0; i < bitmapLength; i++) {            bitmap[i] = new ArrayList<>(64);        }        for (int i = 0; i < 65; i++) {            findNextAvail();        }    }    private static void findNextAvail() {        for (int i = 0; i < bitmapLength; i++) {            if (bitmap[i].size() == 64) {                continue;            }            for (int j = 0; i < 64; j++) {            if (bitmap[i].size() <= j || !bitmap[i].get(j)) {                if (bitmap[i].size() == j) {                bitmap[i].add(true);                } else {                bitmap[i].set(i, true);                }                System.out.println("id :" + (i*64 + j) + " section :" + i);                break;            }            }            break;        }        System.out.println();    }}

 

未完侍。。。

[编织消息框架][netty源码分析]14 PoolChunk 的 PoolSubpage