Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How Netty distributed ByteBuf uses page-level memory allocation

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly shows you "Netty distributed ByteBuf how to use page-level memory allocation", the content is easy to understand, well-organized, hope to help you solve your doubts, the following let Xiaobian lead you to study and learn "Netty distributed ByteBuf how to use page-level memory allocation" this article.

Netty memory allocation data structure

As we mentioned earlier, the unit of netty memory allocation is chunk, and the size of a chunk is 16MB. In fact, each chunk is stored in a chunkList in the form of a bi-directional linked list, while multiple chunkList are also associated with a bi-directional linked list. The structure is as follows:

In chunkList, it is classified into a chunkList according to the memory utilization of chunk, so that when memory is allocated, the corresponding chunkList is found according to the percentage, and a chunk is selected in chunkList for memory allocation.

Let's take a look at the member variable private final PoolChunkList q050 / private final PoolChunkList q025 / private final PoolChunkList q000 / private final PoolChunkList qInit;private final PoolChunkList q075 / private final PoolChunkList q100 in PoolArena.

A total of 6 chunkList are defined and initialized in the constructor

Follow its construction method:

Protected PoolArena (PooledByteBufAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize) {/ / Code omit q100 = new PoolChunkList (null, 100,100,Integer.MAX_VALUE, chunkSize); q075 = new PoolChunkList (q100,75,100, chunkSize); q050 = new PoolChunkList (q075,50,100, chunkSize); q025 = new PoolChunkList (q050,25,75, chunkSize); q000 = new PoolChunkList (q025,1,50, chunkSize); qInit = new PoolChunkList (q000, Integer.MIN_VALUE, 25, chunkSize) / / join q100.prevList (q075); q075.prevList (q050); q050.prevList (q025); q025.prevList (Q000); q000.prevList (null); qInit.prevList (qInit); / / code omission} in a two-way linked list

First of all, each chunkList is created by new PoolChunkList (). Let's take q050 = new PoolChunkList (q075,50,100, chunkSize) as an example to briefly introduce

Q075 indicates that the next node of the current Q50 is q075. We just said that ChunkList is associated through a two-way linked list, so it is not difficult to understand here.

Parameters 50 and 100 indicate that the memory usage of the chunk stored in the current chunkList is between 50% and 100%, and finally the chunkSize sets the size for it.

After the ChunkList is created, set the previous node, q050.prevList (q025), as an example. Here, the last node representing the current chunkList is q025.

After the creation is completed in this way, the node relationship of chunkList becomes as shown in the following figure:

In netty, chunk also contains multiple page, each with a size of 8k. If you want to allocate 16k memory, you can allocate it by finding two consecutive page in chunk. The corresponding relationship is as follows:

In many scenarios, allocating 8k memory to a buffer is also a waste. For example, you only need to allocate a buffer of 2k. If you use 8k, it will cause a waste of 6k. In this case, netty will split the page into multiple subpage, and each subpage size should be specified according to the size of the allocated buffer. For example, to allocate 2k of memory, a page will be divided into four subpage, and the size of each subpage is 2k, as shown in the figure:

Let's look at the property of PoolSubpage, final PoolChunk chunk;private final int memoryMapIdx;private final int runOffset;private final int pageSize; private final long [] bitmap;PoolSubpage prev;PoolSubpage next;boolean doNotDestroy; int elemSize.

Chunk represents which chunk its child pages belong to.

Bitmap is used to record the memory allocation of child pages.

Prev and next, which represent that child pages are associated according to a two-way linked list, pointing to the previous and next nodes, respectively

The elemSize attribute represents how much memory this subpage is divided into. If it is divided according to 1k, it can be divided into eight subpages.

After a brief introduction to the data structure of memory allocation, we begin to analyze the process of netty allocating memory at the page level:

Let's go back to PoolArena's allocate method private void allocate (PoolThreadCache cache, PooledByteBuf buf, final int reqCapacity) {/ / normalize final int normCapacity = normalizeCapacity (reqCapacity); if (isTinyOrSmall (normCapacity)) {int tableIdx; PoolSubpage [] table; / / determine whether it is tinty boolean tiny = isTiny (normCapacity); if (tiny) {/ /

< 512 //缓存分配 if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) { return; } //通过tinyIdx拿到tableIdx tableIdx = tinyIdx(normCapacity); //subpage的数组 table = tinySubpagePools; } else { if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) { return; } tableIdx = smallIdx(normCapacity); table = smallSubpagePools; } //拿到对应的节点 final PoolSubpage head = table[tableIdx]; synchronized (head) { final PoolSubpage s = head.next; //默认情况下, head的next也是自身 if (s != head) { assert s.doNotDestroy && s.elemSize == normCapacity; long handle = s.allocate(); assert handle >

= 0; s.chunk.initBufWithSubpage (buf, handle, reqCapacity); if (tiny) {allocationsTiny.increment ();} else {allocationsSmall.increment ();} return;}} allocateNormal (buf, reqCapacity, normCapacity); return } if (normCapacity maxCapacity) {return false;} / / traverse for down from the head node (PoolChunk cur = head;;) {long handle = cur.allocate (normCapacity); if (handle)

< 0) { cur = cur.next; if (cur == null) { return false; } } else { cur.initBuf(buf, handle, reqCapacity); if (cur.usage() >

= maxUsage) {remove (cur); nextList.add (cur);} return true;} first traverses down from the head node

Long handle = cur.allocate (normCapacity)

For each chunk, an attempt is made to assign

If (handle

< 0) 说明没有分配到, 则通过cur = cur.next找到下一个节点继续进行分配, 我们讲过chunk也是通过双向链表进行关联的, 所以对这块逻辑应该不会陌生 如果handle大于0说明已经分配到了内存, 则通过cur.initBuf(buf, handle, reqCapacity)对byteBuf进行初始化 if (cur.usage() >

= maxUsage) indicates that the memory usage of the current chunk is greater than its maximum utilization, then remove it from the current chunkList via remove (cur) and add it to the next chunkList via nextList.add (cur)

Let's go back to the allocateNormal method of PoolArena:

Let's look at the second step.

PoolChunk c = newChunk (pageSize, maxOrder, pageShifts, chunkSize)

The parameter pageSize here is 8192, which is 8k.

MaxOrder is 11

PageShifts is 13, and the power of 13 of 2 is exactly 8192, which is 8k.

ChunkSize is 16777216, that is, 16MB

The parameter values here can be tracked by debug.

Because our example is out-of-heap memory, newChunk (pageSize, maxOrder, pageShifts, chunkSize), we will go to the newChunk method of DirectArena:

Protected PoolChunk newChunk (int pageSize, int maxOrder, int pageShifts, int chunkSize) {return new PoolChunk (this, allocateDirect (chunkSize), pageSize, maxOrder, pageShifts, chunkSize);} here a chunk is created directly through the constructor

AllocateDirect (chunkSize) A piece of direct memory is applied for by jdk's api, and we follow it to the constructor of PoolChunk:

PoolChunk (PoolArena arena, T memory, int pageSize, int maxOrder, int pageShifts, int chunkSize) {unpooled = false; this.arena = arena; / / memeory is a ByteBuf this.memory = memory; / / 8k this.pageSize = pageSize; / / 13 this.pageShifts = pageShifts; / / 11 this.maxOrder = chunkSize; unusable = (byte) (maxOrder + 1); log2ChunkSize = log2 (chunkSize); subpageOverflowMask = ~ (pageSize-1) FreeBytes = chunkSize; assert maxOrder < 30: "maxOrder should be < 30, but is:" + maxOrder; maxSubpageAllocs = 1

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report