Netty源码分析---PoolChunk深度解析

SpringBoot+Vue+MySQL 高校学科竞赛平台 完整可运行版(源码+文档) 本项目基于SpringBoot+Vue+MySQL构建高校学科竞赛管理平台,覆盖学生、教师、领队教师、管理员四大角色,实现竞赛发布、报名、刷题、评分、公示等全流程闭环管理。系统架构清晰,技术主流,配套完整源码、数据库脚本、万字论文、开题报告、答辩PPT及部署文档,支持一键运行,适用于毕业设计、课程设计及院系二次开发,真正实现“开箱即用”。 阅读详情

PoolChunk 深度解析

一、核心概念

PoolChunk 是 Netty 内存池化管理中的核心类,负责管理一块连续的内存区域。它使用完全平衡二叉树算法来高效地分配和释放内存。

1.1 基本术语

  • Page(页): 可分配的最小内存单元
  • Chunk(块): 由多个 Page 组成的内存块
  • ChunkSize(块大小): chunkSize = 2^maxOrder × pageSize
  • Run: 一个或多个连续的 Page

1.2 默认配置

// 默认值(在 PooledByteBufAllocator 中定义)
pageSize = 8192 (8KB)
maxOrder = 11
chunkSize = 2^11 × 8KB = 16MB

二、核心字段详解

2.1 内存相关字段

final T memory;              // 实际的内存对象(byte[] 或 ByteBuffer)
final int offset;            // 内存偏移量
final int chunkSize;         // Chunk 总大小(默认 16MB)
final int pageSize;          // Page 大小(默认 8KB)
final int maxOrder;          // 二叉树最大深度(默认 11)
private int freeBytes;       // 当前可用字节数

2.2 二叉树管理字段

private final byte[] memoryMap;  // 内存分配状态数组
private final byte[] depthMap;   // 节点深度数组
memoryMap 数组说明

memoryMap 是一个完全平衡二叉树的数组表示,用于跟踪内存分配状态:

  • 数组大小: 2^(maxOrder+1) = 4096(当 maxOrder=11 时)
  • 索引 1: 根节点(代表整个 16MB)
  • 索引 2,3: 第二层节点(各代表 8MB)
  • 索引 2048-4095: 叶子节点(各代表 8KB 的 Page)
memoryMap 值的含义
// 初始化时:memoryMap[id] = depth_of_id
memoryMap[1] = 0    // 根节点,深度为 0
memoryMap[2] = 1    // 第二层,深度为 1
memoryMap[3] = 1
...
memoryMap[2048] = 11  // 叶子节点,深度为 11

// 分配后的状态:
// 1) memoryMap[id] = depth_of_id  => 该节点空闲
// 2) memoryMap[id] > depth_of_id  => 该节点部分被占用
// 3) memoryMap[id] = maxOrder + 1 => 该节点完全被占用(标记为 unusable)

2.3 Subpage 管理字段

private final PoolSubpage<T>[] subpages;  // Subpage 数组
private final int subpageOverflowMask;    // 用于判断是否 >= pageSize
private final int maxSubpageAllocs;       // 最大 Subpage 数量(2^maxOrder)

2.4 链表结构字段

PoolChunkList<T> parent;  // 所属的 ChunkList
PoolChunk<T> prev;        // 前一个 Chunk
PoolChunk<T> next;        // 后一个 Chunk

三、二叉树结构详解

3.1 树的层次结构

depth=0        1 个节点 (16MB)                    [索引 1]
depth=1        2 个节点 (8MB 每个)                [索引 2-3]
depth=2        4 个节点 (4MB 每个)                [索引 4-7]
depth=3        8 个节点 (2MB 每个)                [索引 8-15]
...
depth=11       2048 个节点 (8KB 每个)             [索引 2048-4095]

3.2 节点索引计算

// 父节点索引
parentId = id >>> 1  // 等价于 id / 2

// 左子节点索引
leftChildId = id << 1  // 等价于 id * 2

// 右子节点索引
rightChildId = (id << 1) + 1  // 等价于 id * 2 + 1

// 兄弟节点索引
siblingId = id ^ 1  // 异或运算,奇数变偶数,偶数变奇数

3.3 示例:分配 8KB 内存

初始状态(所有节点值为其深度):
        [1:0]
       /     \
    [2:1]   [3:1]
    /  \     /  \
  [4:2][5:2][6:2][7:2]
  ...

分配 8KB 后(假设分配节点 2048):
1. 找到叶子节点 2048
2. 设置 memoryMap[2048] = 12 (unusable)
3. 更新父节点路径:
   - memoryMap[1024] = min(12, 11) = 11
   - memoryMap[512] = min(11, 10) = 10
   - ... 一直到根节点

四、核心方法详解

4.1 allocate() - 内存分配入口

boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
    final long handle;
    
    // 判断是分配 Run 还是 Subpage
    if ((normCapacity & subpageOverflowMask) != 0) {
        // normCapacity >= pageSize,分配 Run
        handle = allocateRun(normCapacity);
    } else {
        // normCapacity < pageSize,分配 Subpage
        handle = allocateSubpage(normCapacity);
    }
    
    if (handle < 0) {
        return false;  // 分配失败
    }
    
    // 初始化 ByteBuf
    ByteBuffer nioBuffer = cachedNioBuffers != null ? 
                          cachedNioBuffers.pollLast() : null;
    initBuf(buf, nioBuffer, handle, reqCapacity);
    return true;
}
关键点:
  1. subpageOverflowMask: ~(pageSize - 1),用于快速判断大小

    • 当 pageSize = 8192 时,mask = 0xFFFFE000
    • normCapacity & mask != 0 表示 >= 8KB
  2. handle: 一个 long 值,编码了内存位置信息

    • 低 32 位:memoryMap 索引
    • 高 32 位:bitmap 索引(Subpage 使用)

4.2 allocateRun() - 分配连续页

private long allocateRun(int normCapacity) {
    // 计算需要的深度
    // 例如:分配 16KB,需要深度 10 的节点(16KB = 2^10 × 8KB)
    int d = maxOrder - (log2(normCapacity) - pageShifts);
    
    // 在深度 d 查找可用节点
    int id = allocateNode(d);
    if (id < 0) {
        return id;  // 没有可用节点
    }
    
    // 减少可用字节数
    freeBytes -= runLength(id);
    return id;
}
深度计算示例:
// 假设 pageSize = 8KB, maxOrder = 11, pageShifts = 13
// 分配 32KB:
log2(32KB) = 15
d = 11 - (15 - 13) = 9
// 需要深度 9 的节点(大小 = 2^(11-9) × 8KB = 32KB)

// 分配 8KB:
log2(8KB) = 13
d = 11 - (13 - 13) = 11
// 需要深度 11 的节点(叶子节点)

4.3 allocateNode() - 查找可用节点

private int allocateNode(int d) {
    int id = 1;  // 从根节点开始
    int initial = -(1 << d);  // 用于判断是否到达目标深度
    byte val = value(id);
    
    if (val > d) {
        return -1;  // 根节点都不满足,无法分配
    }
    
    // 向下遍历,直到找到深度为 d 的可用节点
    while (val < d || (id & initial) == 0) {
        id <<= 1;  // 尝试左子节点
        val = value(id);
        
        if (val > d) {
            id ^= 1;  // 左子节点不可用,尝试右子节点
            val = value(id);
        }
    }
    
    // 标记为已使用
    setValue(id, unusable);
    updateParentsAlloc(id);
    return id;
}
算法流程示例:
查找深度 2 的节点:
1. 从根节点 1 开始,val=0 < 2,继续
2. 移到左子节点 2,val=1 < 2,继续
3. 移到左子节点 4,val=2,且 id & initial == 1<<2,找到!
4. 标记节点 4 为 unusable
5. 更新父节点状态

4.4 allocateSubpage() - 分配小内存

private long allocateSubpage(int normCapacity) {
    // 获取对应大小的 Subpage 池头节点
    PoolSubpage<T> head = arena.findSubpagePoolHead(normCapacity);
    int d = maxOrder;  // Subpage 只能从叶子节点分配
    
    synchronized (head) {
        // 分配一个 Page
        int id = allocateNode(d);
        if (id < 0) {
            return id;
        }
        
        final PoolSubpage<T>[] subpages = this.subpages;
        final int pageSize = this.pageSize;
        
        freeBytes -= pageSize;
        
        int subpageIdx = subpageIdx(id);
        PoolSubpage<T> subpage = subpages[subpageIdx];
        
        if (subpage == null) {
            // 创建新的 Subpage
            subpage = new PoolSubpage<T>(head, this, id, 
                                        runOffset(id), pageSize, normCapacity);
            subpages[subpageIdx] = subpage;
        } else {
            // 重新初始化已存在的 Subpage
            subpage.init(head, normCapacity);
        }
        
        return subpage.allocate();
    }
}
Subpage 索引计算:
private int subpageIdx(int memoryMapIdx) {
    // 移除最高位,得到偏移量
    return memoryMapIdx ^ maxSubpageAllocs;
    
    // 例如:memoryMapIdx = 2048, maxSubpageAllocs = 2048
    // subpageIdx = 2048 ^ 2048 = 0
    // memoryMapIdx = 2049
    // subpageIdx = 2049 ^ 2048 = 1
}

4.5 updateParentsAlloc() - 更新父节点(分配时)

private void updateParentsAlloc(int id) {
    while (id > 1) {
        int parentId = id >>> 1;
        byte val1 = value(id);
        byte val2 = value(id ^ 1);  // 兄弟节点
        
        // 父节点的值 = min(左子节点, 右子节点)
        byte val = val1 < val2 ? val1 : val2;
        setValue(parentId, val);
        
        id = parentId;
    }
}
更新示例:
分配节点 8 后:
1. memoryMap[8] = 12 (unusable)
2. 更新父节点 4: min(memoryMap[8], memoryMap[9]) = min(12, 3) = 3
3. 更新父节点 2: min(memoryMap[4], memoryMap[5]) = min(3, 2) = 2
4. 更新父节点 1: min(memoryMap[2], memoryMap[3]) = min(2, 1) = 1

4.6 free() - 释放内存

void free(long handle, ByteBuffer nioBuffer) {
    int memoryMapIdx = memoryMapIdx(handle);
    int bitmapIdx = bitmapIdx(handle);
    
    if (bitmapIdx != 0) {
        // 释放 Subpage
        PoolSubpage<T> subpage = subpages[subpageIdx(memoryMapIdx)];
        PoolSubpage<T> head = arena.findSubpagePoolHead(subpage.elemSize);
        
        synchronized (head) {
            if (subpage.free(head, bitmapIdx & 0x3FFFFFFF)) {
                return;  // Subpage 还有其他分配,不释放整个 Page
            }
        }
    }
    
    // 释放 Run 或完全空闲的 Page
    freeBytes += runLength(memoryMapIdx);
    setValue(memoryMapIdx, depth(memoryMapIdx));  // 恢复为深度值
    updateParentsFree(memoryMapIdx);
    
    // 缓存 ByteBuffer
    if (nioBuffer != null && cachedNioBuffers != null &&
        cachedNioBuffers.size() < PooledByteBufAllocator.DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK) {
        cachedNioBuffers.offer(nioBuffer);
    }
}

4.7 updateParentsFree() - 更新父节点(释放时)

private void updateParentsFree(int id) {
    int logChild = depth(id) + 1;
    
    while (id > 1) {
        int parentId = id >>> 1;
        byte val1 = value(id);
        byte val2 = value(id ^ 1);
        logChild -= 1;
        
        // 如果两个子节点都完全空闲,父节点也标记为完全空闲
        if (val1 == logChild && val2 == logChild) {
            setValue(parentId, (byte) (logChild - 1));
        } else {
            byte val = val1 < val2 ? val1 : val2;
            setValue(parentId, val);
        }
        
        id = parentId;
    }
}

五、关键辅助方法

5.1 位置计算方法

// 计算节点代表的内存大小
private int runLength(int id) {
    return 1 << (log2ChunkSize - depth(id));
    // 例如:depth=0, runLength = 1 << (24-0) = 16MB
    //      depth=11, runLength = 1 << (24-11) = 8KB
}

// 计算节点在 Chunk 中的偏移量
private int runOffset(int id) {
    int shift = id ^ (1 << depth(id));
    return shift * runLength(id);
    // 例如:id=2048 (第一个叶子节点)
    //      shift = 2048 ^ 2048 = 0
    //      offset = 0 × 8KB = 0
}

5.2 Handle 编解码

// Handle 结构(64 位):
// [高 32 位: bitmapIdx] [低 32 位: memoryMapIdx]

private static int memoryMapIdx(long handle) {
    return (int) handle;  // 取低 32 位
}

private static int bitmapIdx(long handle) {
    return (int) (handle >>> Integer.SIZE);  // 取高 32 位
}

六、使用场景分析

6.1 分配 16KB 内存

// 1. 调用 allocate(buf, 16384, 16384)
// 2. 16384 >= 8192,调用 allocateRun(16384)
// 3. 计算深度:d = 11 - (14 - 13) = 10
// 4. 在深度 10 查找节点(大小 16KB)
// 5. 找到节点,标记为 unusable
// 6. 更新父节点状态
// 7. freeBytes -= 16384

6.2 分配 512 字节内存

// 1. 调用 allocate(buf, 512, 512)
// 2. 512 < 8192,调用 allocateSubpage(512)
// 3. 在深度 11 分配一个 Page(8KB)
// 4. 创建或初始化 PoolSubpage
// 5. 在 Subpage 中分配 512 字节
// 6. freeBytes -= 8192(整个 Page)

七、性能优化设计

7.1 缓存优化

// ByteBuffer 缓存,减少 GC
private final Deque<ByteBuffer> cachedNioBuffers;

// 使用两个数组分离关注点
private final byte[] memoryMap;  // 分配状态
private final byte[] depthMap;   // 节点深度(不变)

7.2 位运算优化

// 使用位运算代替除法和取模
parentId = id >>> 1;           // 代替 id / 2
leftChildId = id << 1;         // 代替 id * 2
siblingId = id ^ 1;            // 快速获取兄弟节点

7.3 快速判断

// 使用掩码快速判断大小
if ((normCapacity & subpageOverflowMask) != 0) {
    // >= pageSize
}

八、总结

8.1 核心特点

  1. 完全平衡二叉树: 高效的内存分配和释放
  2. 伙伴系统: 支持内存合并,减少碎片
  3. 分层管理: Run(大内存)和 Subpage(小内存)
  4. 位运算优化: 快速计算和判断

8.2 时间复杂度

  • 分配: O(log n),n 为树的深度(maxOrder)
  • 释放: O(log n)
  • 查找: O(log n)

8.3 空间复杂度

  • memoryMap: 2^(maxOrder+1) 字节 = 4KB
  • depthMap: 2^(maxOrder+1) 字节 = 4KB
  • subpages: 2^maxOrder 个引用 = 16KB(64 位系统)
  • 总开销: 约 24KB(管理 16MB 内存)

8.4 适用场景

  • 需要频繁分配和释放内存的场景
  • 内存大小范围广泛(从几百字节到几 MB)
  • 对性能要求高的网络应用
  • 需要减少 GC 压力的场景
基于3D相机的人体穴位识别与标注系统——完整Python实现方案 摘要 本文提出了一种基于3D相机的人体穴位识别与标注系统完整实现方案。系统采用Intel RealSense D435相机实时采集RGB-D数据,结合MediaPipe Pose模型进行人体33个关键骨骼点的三维姿态估计。通过建立穴位与骨骼关键点的映射关系,利用相机内参和深度信息将二维图像坐标转换为三维空间坐标。系统采用模块化设计,包含数据采集层、算法处理层、坐标转换层和可视化层,实现了穴位定位、三维坐标转换和点云可视化功能。关键技术包括:基于骨度折量法的穴位映射算法、深度图像到三维点云的转换方法,以及Op 阅读详情

相关推荐

SCHUNK SVH五指灵巧手 | 熵洛智能

雄克仿真五指机械手产品系列可以如人手操作那般完美地完成抓取操作。电子装置完全集成于腕关节中,使五指机械手几乎可以完成所有的人体手部动作。凭借带有9个驱动器的运动指骨,机械手可高精度地 执行多种抓取操作。富有弹性的抓取表面确保了对物体的可靠抓取。除了开启抓取和操作任务的全新领域之外,雄克还为在五指机械手的手势基础上进行人与机器人的交流开创了无限可能。编辑切换为居中添加图片注释,不超过 140 字(可选)产品特点:机械手有左手或右手两种版本适合移动应用耗能低,使用 24 V DC 在腕关节处完整集成了控制、调节

ShannonTech的博客 1334

Netty源码分析-PoolChunk

上图中是一个默认大小的chunk, 由2048个page组成了一个chunk,一个page的大小为8192, chunk之上有11层节点,最后一层节点数与page数量相等。每次内存分配需要保证内存的连续性,这样才能简单的操作分配到的内存,因此这里构造了一颗完整的平衡二叉树,所有子节点的管理的内存也属于其父节点。如果我们想获取一个8K的内存,则只需在第11层找一个可用节点...

大新博客 733

CANdelaStudio实战:如何用19服务快速编辑DTC快照数据(附Excel模板)

本文详细介绍了在CANdelaStudio中利用19服务高效编辑DTC快照数据的进阶技巧。通过导出DTC池至Excel进行批量编辑,结合‘Copy from DTC Pool’功能实现配置复用,并分享了构建自定义Excel模板与字段映射的实用方法,帮助工程师将繁琐的手动配置转化为工程化的批量处理,大幅提升诊断数据库开发效率。

weixin_29230773的博客 192

Netty内存分配机制深度解读:PoolChunk与Page管理

Netty 通过二叉树结构高效管理 Chunk 内 Page 的分配与回收,实现 O(log n) 的分配效率,极大提升了高并发场景下的内存利用率和系统性能。其分级池化思想、灵活参数配置、源码实现与业务集成,为现代网络编程提供坚实基础。知其然,更知其所以然。理解 Netty PoolChunk 与 Page 管理机制,是迈向高性能网络编程的必修课。掌握原理、熟悉源码、灵活调优、善用工具,方能在实际项目中游刃有余。

IT技术学习与工作笔记分享 637

OCR开发实战:如何用PaddleOCR C++版实现本地文字识别(附模型文件处理技巧)

本文详细介绍了如何使用PaddleOCR C++版实现本地文字识别,包括环境搭建、工程编译、运行时优化等全流程。重点讲解了在VS2019/VS2022环境下配置PaddleOCR的CPU推理性能优化技巧,以及模型文件处理的实际应用方法,帮助开发者高效完成OCR本地化部署。

devops8pract的博客 335

优化求解器性能:当分支切割算法中的gap停滞不前时如何应对

本文深入探讨了当分支切割算法求解复杂整数规划问题时,gap停滞不前的根本原因与应对策略。文章指出gap停滞源于上界(找不到更优整数解)或下界(证明过程缓慢)提升受阻,并提供了从模型改写、自定义割平面、调整搜索策略到参数调优等一系列实战方法,帮助优化工程师有效打破求解僵局,推动gap下降。

weixin_29294597的博客 381

Netty学习之旅:源码分析Netty内存池分配基础数据结构(PoolArena、PoolChunk、PoolSubpage)

1、Netty 内存分配基础数据结构 Netty 预先申请一大块连续的内存(用 PoolArena 类表示),然后每一 PoolArena 包含一系列的 Chunk, 用 PoolChunk 表示,然后每一个 Chunk 包含一列的 PoolSubpage,每个 PoolSubpage 由大小相等的块(Region)组成,每个 PoolSubpage 块大小由第一次从 PoolSubpage申请...

中间件兴趣圈 5311

PreScan快速入门到精通第三十九讲基于车道线识别传感器的车道保持辅助算法Demo讲解

车道保持辅助系统使用一个前置的摄像头,一般安装在车内后视镜附近,用来检测车辆前方的车道线,并监测车辆在其车道上的位置。在有电动助力转向EPS的车辆中,它轻轻地,但明显地反转向,以保持车辆在车道上。在简单车辆动力学的Simulink模型中,一个25%的油门开度常数被设定为输入,作为车辆行驶的纵向动力。首先是近似的角度α,它是传感器航向(=车辆航向)与右侧车道车道线的切线的近似角。一个配备了车道线传感器和简单动力学模型的车辆(MAZDA),将在没有任何规定轨迹的情况下跟随道路车道线行驶。3D浏览器中的多视图。

小明师兄的博客 1843

Netty PoolChunk 内存管理完全二叉树详解 —— memoryMap 与 depthMap 深度剖析

在 Netty 的内存池体系(PoolArena/PoolChunk)中,完全二叉树结构的 memoryMap 与 depthMap,是实现高效、低碎片内存分配与回收的关键。它借鉴了 jemalloc、tcmalloc 等业界内存分配器的分级、切分思想,以 Java 数组形式实现,兼顾性能与易用性。深度不变记 depthMap,状态变动看 memoryMap分配下沉,回收上浮全部可用=深度,部分可用=深度+1,全占用=maxOrder+1。

IT技术学习与工作笔记分享 802

<PLC><socket><汇川>汇川PLC使用socket与其他控制器(如上位机)通讯模板程序示例

以上介绍了汇川PLC通用socket通讯的示例,事实上,汇川的官方手册也有使用示例,可以直接仿照使用,也可以加以修改。

用沸腾的热血,支付我们的人生吧! 3249

一文搞懂多速率信号处理中信号插值的本质:从插 0、插原值到线性插值!

信号插值在数字信号处理中经常被使用,但“插值”背后究竟发生了什么,却常被忽略。插0、插原值、线性插值看似只是不同的实现方式,实则对应着完全不同的频域效应与滤波特性。本文将结合公式与MATLAB仿真,深入剖析插0、插原值与线性插值三种典型策略的本质区别。

m0_66360845的博客 922

Netty学习之旅----源码分析内存分配与释放原理

互联网大厂比较喜欢的人才特点:对技术有热情,强硬的技术基础实力;主动,善于团队协作,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。下面有部分截图希望能对大家有所帮助。

2401_84092574的博客 942

YOLO26改进策略【卷积层】| SPD-Conv 针对小目标和低分辨率图像的检测任务

SPD-Conv是一种新的 CNN 构建模块,用于替代传统 CNN 架构中使用的步长卷积(strided convolution)和池化(pooling)层,它由空间到深度(Space-to-depth,SPD)层和非步长卷积(non - strided convolution)层组成。

Limiiiing的博客 359

Netty内存池设计原理与源码解析

Netty内存池设计原理与源码解析 摘要:Netty内存池通过分层管理机制优化高并发网络应用中的内存分配性能。其核心设计包括:1)分层分配策略,将内存分为Tiny/Small/Normal/Huge四类,分别采用位图、二叉树等不同分配方式;2)借鉴Jemalloc算法,通过PoolArena分片管理、PoolThreadCache线程本地缓存降低锁竞争;3)引用计数与Recycler机制实现内存复用。关键优化点包括:小内存使用PoolSubpage位图管理,普通内存通过PoolChunk二叉树分配,大内存直

持续输出Java相关知识 1143

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

从0到1理解Netty内存管理:ByteBuf池化技术如何拯救OOM危机

Netty作为高性能网络编程框架,其内存管理机制是实现高并发场景下稳定运行的核心保障。本文将深入剖析Netty的ByteBuf池化技术,带你理解它如何通过创新的内存复用机制解决传统NIO编程中的内存泄漏问题,让你的应用轻松应对高负载挑战。 ## 为什么Netty需要特殊的内存管理? 在传统Java NIO编程中,ByteBuffer的创建和销毁成本高昂,尤其是堆外内存的分配回收会导致频繁的系统

gitblog_00903的博客 877

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

2018深入浅出Netty源码剖析最新

课程目标:1、深入了解Netty内部实现2、深入理解Netty的设计思想3、完全掌控Netty的高级研发适合人群1、想自己写高性能服务器,替换Tomcat,jetty2、想完全随心所欲的掌控Netty的每一个细节3、想成为一名高级Netty研发工程师官方课程链接:http://www.xuetuwuyou.com/course/157课程目录:课时1:重要声明课时2:Netty源码剖析简介...

weixin_44222629的博客 515

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 298

信创环境下PageOffice文档控件适配与实践

信创适配做到文档控件这一层,拼的已经不是"有没有国产版本",而是同一个功能在两类终端上是否真的等价。等价的标准很具体:同一次点击能得到同样的结果,同一份公文能得到同样的版式,同一个项目不需要维护两套代码。这背后是三件并不轻松的工作:服务端用一套接口同时支撑两类终端,客户端把两种系统与四种芯片的安装包分发清楚,文档内核层由产品侧跟着 WPS 的版本走。浏览器这一层的压力,则被收进了产品自己的窗口里——升级节奏由产品掌握,不再交给运气。

zi_wu_xian的专栏 327

第三篇 第 6 课

前置:第三篇第 1 课(stdx 引入),第二篇第 1 课(std.regex)。环境:仓颉 SDK 1.2.0。本文所有代码与输出均逐行实测。

weixin_41618057的博客 516

V8 机制、手写核心函数与 TypeScript 类型体操

或固定初始化(如数组先定长、对象先给全字段)保持类型与形状稳定;这些都比"换框架"更基础。只能处理纯数据(丢函数、Date、RegExp、循环引用报错)。生产级深拷贝要处理:原始值短路、循环引用、V8(Chrome / Node 的 JS 引擎)不是"解释一行跑一行"那么简单,它用。图:V8 执行流程——解释执行 + 热点优化,优化失败会 Deopt 回退。JS 内存自动管理,但"自动"不等于"不会漏"。是"固定间隔最多执行一次"。手写 Promise 是"懂异步"的试金石。是"停下后才执行最后一次",

qq_38468358的博客 351

【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端

上一篇讲了 MCP 的概念:标准协议、三大角色、M+N 替代 M×N。

nice_lcj520的博客 538

Java 集合容器高频面试题全解:HashMap 树化阈值、1.7 死循环与 ConcurrentHashMap 演进(2026 招聘 JD 真题复盘)

HashMap 树化阈值 8 的泊松分布依据、退化阈值 6 的防抖设计、JDK 1.7 头插成环死循环的排查与修复、1.8 尾插后为何仍线程不安全、ConcurrentHashMap 放弃分段锁的原因与 ForwardingNode 协作扩容、computeIfAbsent 死锁陷阱、大集合找重复的场景题选型,附三层追问链自测。题目来源为 38 期公开招聘 JD 样本与字节、拼多多、建行、美团、快手公开面经。

蒙眼过河 420

spdlog 同步日志库使用详解

spdlog是一个轻量级 C++ 日志库,支持同步日志、异步日志、多线程日志、日志文件轮转和自定义日志格式。对于嵌入式 Linux 应用开发,我建议先使用。它可以帮我们完成:日志级别过滤。时间戳和线程 ID 输出。日志格式化。终端和文件输出。多线程安全写入。日志文件按大小或时间轮转。我们不需要自己实现互斥锁、文件写入、日志格式化和轮转等底层功能。

zengjiajun2006的博客 1120

JavaSE通关手册:数据类型与变量

代码无需额外处理,编译时编译器自动完成转换。

xys_678的博客 221

Java 多态 学习笔记

多态是面向对象编程的重要特性,指同一操作作用于不同对象时产生不同行为。其核心在于“父类引用指向子类对象”,结合方法重写实现运行时动态绑定。多态使代码更灵活、可扩展,如用Person p = new Student();统一处理各类人员注册,无需修改调用逻辑。但多态无法直接调用子类特有方法,需通过instanceof判断并强制转换。编译时看左边(类型),运行时看右边(实际对象),实现解耦与维护便利。

AA_AA114514的博客 367

IDEA 简介:从零认识 IntelliJ IDEA

IDEA 全称,是由 JetBrains 公司开发的一款主流 Java 集成开发环境(IDE)。它集代码编辑、编译、调试、测试、版本控制、构建管理等功能于一体,被大量 Java 开发者视为日常开发的首选工具。所谓 IDE(Integrated Development Environment,集成开发环境),就是把写代码所需的各类工具整合到同一个界面中。相比只用文本编辑器加命令行编译,IDE 能显著减少重复操作,让开发者把精力集中在业务逻辑上。

ztI10的博客 174

Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

【代码】Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

m0_64476639的博客 341
上一篇: Netty源码分析----FastThreadLocal深度解析
下一篇: Netty源码分析---Reactor线程模型深度解析(一)
不早睡不改名@
博客等级 码龄5年 536粉丝 306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值