Nettyメモリ管理PoolChunkの詳細

4407 ワード

数年前、Cメモリの手動管理からjavaの自動GCに上昇したのは、歴史的な大きな進歩だった.しかし、数年後、nettyのメモリはまた曲線的に手動管理モデルに戻り、マルクス哲学観を証明している:社会はいつも螺旋式に前進し、永遠の最良はない.確かに、メモリ管理について言えば、GCがプログラマーに与える価値は言うまでもなく、プログラマーの負担を大幅に低減しただけでなく、メモリ管理によるCrashの悩みも大幅に低減したが、手動のメモリ管理がより適切である場合が多い.次に、Nettyのメモリ管理をいくつかの紙面で深く分析する準備をします.PoolChunkメモリを簡単に操作するためには、割り当てられたメモリのたびに連続することを保証する必要があります.Nettyの最下位レベルのメモリ割り当てと回収管理は主にPoolChunkによって実現され、その内部にはバランスツリーmemoryMapが維持され、すべてのサブノードが管理するメモリも親ノードに属している.
poolChunkのデフォルトは2048個のpageで構成され、1個のpageのデフォルトサイズは8 kであり、図中のノードの値は配列memoryMapの下付きである.1、サイズ8 kのメモリを割り当てる必要がある場合は、11階で最初に使用可能なノードを見つけるだけです.2、サイズ16 kのメモリを割り当てる必要がある場合は、10階で最初に使用可能なノードを見つけるだけです.3.ノード1024に既に割り当てられたサブノード2048が存在する場合、そのノードは割り当てられない.サイズ16 kのメモリを割り当てる必要がある場合、この時点でノード2048が割り当てられ、ノード2049が割り当てられていない場合、ノード1024を直接割り当てることはできない.このノードは現在8 kのメモリしか残っていないからである.poolChunkの内部では、各割り当てメモリサイズが8 K*(2 n)であることが保証されています.chunkSize/(2 k)のノードを割り当てるには、深さkのレイヤで左からノードをマッチングする必要があります.では、指定したメモリにどのように迅速に割り当てますか?MemoryMap初期化:
memoryMap = new byte[maxSubpageAllocs << 1];
depthMap = new byte[memoryMap.length];
int memoryMapIndex = 1;
for (int d = 0; d <= maxOrder; ++ d) { // move down the tree one level at a time
    int depth = 1 << d;
    for (int p = 0; p < depth; ++ p) {
        // in each level traverse left to right and set value to the depth of subtree
        memoryMap[memoryMapIndex] = (byte) d;
        depthMap[memoryMapIndex] = (byte) d;
        memoryMapIndex ++;
    }
}

memoryMap配列の各位置に保存されているのは、そのノードが存在するレイヤ数です.どのような役割がありますか?ノード512の場合、その層数は9であり、1、memoryMap[512]=9の場合、それ自体が次のすべてのサブノードに割り当てられることを示す.2、memoryMap[512]=10の場合、ノード512の下にサブノードが割り当てられていることを示すと、そのノードは直接割り当てられず、そのサブノードの10番目のレイヤには未割り当てのノードが存在する.3、memoryMap[512]=12(つまり総層数+1)の場合、割り当て可能な深さが総層数よりも大きい場合は、そのノードの下にあるすべてのサブノードが割り当てられていることを示します.PoolChunkにメモリを申請する方法を見てみましょう.
long allocate(int normCapacity) {
    if ((normCapacity & subpageOverflowMask) != 0) { // >= pageSize
        return allocateRun(normCapacity);
    } else {
        return allocateSubpage(normCapacity);
    }
}

1.割り当てが必要なメモリがpageSizeより大きい場合、allocateRunを使用してメモリ割り当てを実現する.2、そうでない場合はメソッドallocateSubpageを使用してメモリを割り当て、allocateSubpage実装では1つのpageを多段に分割してメモリ割り当てを行う.
ここではまずallocateRunがどのように実現されているかを見てみましょう.
private long allocateRun(int normCapacity) {
    int d = maxOrder - (log2(normCapacity) - pageShifts);
    int id = allocateNode(d);
    if (id < 0) {
        return id;
    }
    freeBytes -= runLength(id);
    return id;
}

1、normCapacityは、申請サイズが1000のメモリ、実際の申請のメモリサイズが1024のように処理された値である.2、d=maxOrder-(log 2(normCapacity)-pageShifts)は、ツリーのd層でノードマッチングを開始する必要があることを決定することができる.ここでpageShiftsのデフォルト値は13ですが、なぜ13ですか?メソッドallocateRunは、リクエストメモリサイズが2^13(8192)より大きい場合にのみ、メモリを割り当てるために使用されます.3、メソッドallocateNodeは、ツリー内のノードマッチングを実現します.具体的には、次のようになります.
private int allocateNode(int d) {
    int id = 1;
    int initial = - (1 << d); 
    //value(id)=memoryMap[id] 
    byte val = value(id); 
    if (val > d) { // unusable
        return -1;
    }
    while (val < d || (id & initial) == 0) { // id & initial == 1 << d for all ids at depth d, for < d it is 0
        id <<= 1;
        val = value(id);
        if (val > d) {
            id ^= 1;
            val = value(id);
        }
    }
    byte value = value(id);
    assert value == d && (id & initial) == 1 << d : String.format("val = %d, id & initial = %d, d = %d",
            value, id & initial, d);
    setValue(id, unusable); // mark as unusable
    updateParentsAlloc(id);
    return id;
}

1、ルートノードから巡回し、現在のノードのval 2、val>dの場合、サブノードが割り当てられている場合があり、残りのノードのメモリサイズが足りない場合は、兄弟ノードで検索を続行する必要があります.3、割り当てに成功したノードは使用不可とマークし、再割り当てを防止し、memoryMap対応位置で12に更新する必要がある.4、分配ノードが完成した後、その親ノードの状態も更新する必要があり、さらに上位の親ノードの更新を引き起こす可能性があり、以下のように実現する.
private void updateParentsAlloc(int id) {
    while (id > 1) {
        int parentId = id >>> 1;
        byte val1 = value(id);
        byte val2 = value(id ^ 1);
        byte val = val1 < val2 ? val1 : val2;
        setValue(parentId, val);
        id = parentId;
    }
}

例えば、ノード2048が割り当てられ、更新プロセスは、poolChunkベースのノード割り当てがこれまでに完了した.
いいと思います.いいと思います.応援してください.伝言を歓迎します.あるいは、私のグループに入ってください.855801563は「アーキテクチャ資料特集目合集90期」、「BATJTMD大工場JAVA面接真題1000+」を受け取ります.本グループは交流技術を勉強し、面接の機会を分かち合い、広告を拒否します.私もグループ内で不定期に問題を答え、検討します.