【深入理解 ByteBuf 之一】 release() 的必要性

引言

开个新坑 【深入理解 ByteBuf】 至于为什么,本篇就是原因
我大概会花一个较长的时间来剖析 Netty 对于 ByteBuf 的实现,对象池的设计,从分配到释放重用,希望可以借此学习理解对象池的设计思想,以及搞清楚,我们不 release ByteBuf 泄露的究竟是什么,
以文章形式作为记录,希望对之后的开发设计有所启发,如果本系列文章帮助到了你,不胜荣幸。

ByteBuf 不 release 造成的内存泄露

首先模拟内存泄露的场景,这里我写了几个接口先通过 /buffer 接口进行循环分配,/metric 接口可以查看当前 分配器 的一些状态参数

@Slf4j
@RequestMapping("/api/bytebuf")
@RestController
public class ByteBufTestController {private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3,5,10, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10));@RequestMapping("/bufferNoPool")public ResultVO bufferNoPool() {final Runnable runnable = new Runnable() {@Overridepublic void run() {try {while (true) {final ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer(1024 * 10);buffer.writeBytes(new byte[1024 * 10]);buffer.retain();}}catch (Exception e){log.error("run buffer error" ,e);}}};Thread thread = new Thread(runnable);thread.start();return ResultVO.successResult(PooledByteBufAllocator.DEFAULT.toString());}@RequestMapping("/buffer")public ResultVO buffer() {final Runnable runnable = new Runnable() {@Overridepublic void run() {try {while (true) {final ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer(1024 * 10);buffer.writeBytes(new byte[1024 * 10]);buffer.retain();}}catch (Exception e){log.error("run buffer error" ,e);}}};threadPoolExecutor.submit(runnable);threadPoolExecutor.submit(runnable);return ResultVO.successResult(PooledByteBufAllocator.DEFAULT.toString());}@RequestMapping("/bufferAndRelease")public ResultVO bufferAndRelease() {final Runnable runnable = new Runnable() {@Overridepublic void run() {try {while (true) {final ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer(1024 * 10);buffer.writeBytes(new byte[1024 * 10]);buffer.release();}}catch (Exception e){log.error("run bufferAndRelease error" ,e);}}};threadPoolExecutor.submit(runnable);threadPoolExecutor.submit(runnable);return ResultVO.successResult(PooledByteBufAllocator.DEFAULT.toString());}@RequestMapping("/metric")public ResultVO metric() {final PooledByteBufAllocatorMetric metric = PooledByteBufAllocator.DEFAULT.metric();ResultMap resultMap = new ResultMap();resultMap.put("numDirectArenas", metric.numDirectArenas());resultMap.put("usedDirectMemory", metric.usedDirectMemory());resultMap.put("metric", metric.toString());return ResultVO.successResult(resultMap);}}

配置好你本地的启动项,为了观测明显我分配了 2G 的可用直接内存

-Xms2G
-Xmx2G
-XX:MaxDirectMemorySize=2G
-XX:ThreadStackSize=512
-XX:MaxMetaspaceSize=256M
-XX:MetaspaceSize=256M
-Dio.netty.leakDetection.level=paranoid
--add-opens
java.base/java.lang=ALL-UNNAMED
--add-opens
java.base/java.io=ALL-UNNAMED
--add-opens
java.base/java.math=ALL-UNNAMED
--add-opens
java.base/java.net=ALL-UNNAMED
--add-opens
java.base/java.nio=ALL-UNNAMED
--add-opens
java.base/java.security=ALL-UNNAMED
--add-opens
java.base/java.text=ALL-UNNAMED
--add-opens
java.base/java.time=ALL-UNNAMED
--add-opens
java.base/java.util=ALL-UNNAMED
--add-opens
java.base/JDK.internal.access=ALL-UNNAMED
--add-opens
java.base/JDK.internal.misc=ALL-UNNAMED
--add-opens
java.base/sun.net.util=ALL-UNNAMED

在这里插入图片描述

那项目刚启动可以观察到,在活动监视器中的内存占用是 1G 多

在这里插入图片描述

运行时可以尝试通过 JProfiler 来监听内存和 GC 情况,下面是正常运行的检测

在这里插入图片描述

在这里插入图片描述

请求分配并且不释放时,堆内存增长,经过 GC 后呈现尖刺状,最后趋近平稳是线程分配已经报错,无法进行分配了,可以看到整个 Java 程序占用 4G 多而且一直不会释放。

在这里插入图片描述

再次 GC 后回归正常

在这里插入图片描述

但是整个程序堆外内存已经无法分配了

在这里插入图片描述

Exception in thread "Thread-53" java.lang.OutOfMemoryError: Cannot reserve 4194304 bytes of direct buffer memory (allocated: 2146073230, limit: 2147483648)at java.base/java.nio.Bits.reserveMemory(Bits.java:178)at java.base/java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:121)at java.base/java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:332)at io.netty.buffer.PoolArena$DirectArena.allocateDirect(PoolArena.java:701)at io.netty.buffer.PoolArena$DirectArena.newChunk(PoolArena.java:676)at io.netty.buffer.PoolArena.allocateNormal(PoolArena.java:215)at io.netty.buffer.PoolArena.tcacheAllocateSmall(PoolArena.java:180)at io.netty.buffer.PoolArena.allocate(PoolArena.java:137)at io.netty.buffer.PoolArena.allocate(PoolArena.java:129)at io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:400)at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:188)at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:179)at io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:116)

可以看到这里报错的限制值与配置的 2G 是一致的

在这里插入图片描述

那其实能看到明显的堆内存浮动是因为我代码中分配 ByteBuf 的时候同时 new 了一个 byte 数组,去掉这行代码同样可以观察到堆外内存一直居高不下,堆内存没有影响,只有一次明显的 GC 活动

 buffer.writeBytes(new byte[1024 * 10]);

在这里插入图片描述

这说明如果你没有正确的 release ByteBuf 会导致堆外内存无法释放,从而导致内存泄露,再次尝试申请会报 OOM 错误。

也就是说即使 JVM 帮你回收了没有引用的 ByteBuf,但是 ByteBuf 占用的堆外内存也不会得到释放

at java.base/java.nio.Bits.reserveMemory(Bits.java:178)

在这里插入图片描述

如果调用的是分配并正确释放方法,可以观察到内存的使用是稳定的,GC 来自于堆内引用的申请和释放

在这里插入图片描述

至此已经复现了问题,并认识到了其严重性,那么具体到代码里,究竟是什么没有释放呢?Netty 为什么没有相关容错的机制?

这个问题勾起了我的好奇心,而故事可能要从对象池的设计讲起

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/599714.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

XTU OJ 1525瓷片

题意 给定一个2n的地面&#xff0c;用11和1*2的瓷片铺满&#xff0c;问有多少种方案 数据范围 n<30 输入 3 1 2 30 输出 2 7 1084493574452273 代码 #include<stdio.h>int main() {int t;scanf("%d",&t);long long a[40];a[0]1,a[1]2,a[2]7;fo…

晶圆代工降价竞争进入白热化,降幅最高15% | 百能云芯

随着半导体产业的不确定性和市况回落&#xff0c;晶圆代工市场再次掀起波澜&#xff0c;“降价大军”再添猛将。 据综合媒体报道&#xff0c;传三星计划在2024年第一季度调降晶圆代工报价&#xff0c;提供5%至15%的折扣&#xff0c;并表示愿意进一步协商。 台积电根据客户的投产…

Java集合框架深度解析-ArrayList

Java的集合框架提供了一组实现常用数据结构的类和接口。理解集合框架对于Java程序员来说至关重要&#xff0c;因为它们在日常编程中广泛应用。 为什么需要集合框架&#xff1f; 在编程中&#xff0c;我们经常需要存储和操作一组对象。集合框架提供了用于表示和操作对象组的通…

从 YOLOv1 到 YOLO-NAS 的所有 YOLO 模型:论文解析

在计算机视觉的浩瀚领域&#xff0c;有一支耀眼的明星&#xff0c;她的名字传颂着革新与突破的传奇——YOLO&#xff08;You Only Look Once&#xff09;。回溯时光&#xff0c;走进这个引人注目的名字背后&#xff0c;我们仿佛穿越进一幅画卷&#xff0c;一幅展现创新魅力与技…

Unity之预制体与变体

PS:不用说了&#xff0c;我在写博客就是在摸鱼 一、预制体 不知道大家小时候有没有看过火影&#xff0c;记得剧情最开始的时候水木哄骗鸣人去偷封印之书&#xff0c;反而让鸣人学会了多重影分身之术&#xff1a; 好了&#xff0c;小编绞尽脑子终于想好怎么向大家介绍预制体了&a…

【漏洞复现】通天星CMSV6车载监控平台任意文件下载漏洞

Nx01 产品简介 深圳市通天星科技有限公司&#xff0c;是一家以从事计算机、通信和其他电子设备制造业为主的企业。通天星车载视频监控平台软件拥有多种语言版本。应用于公交车车载视频监控、校车车载视频监控、大巴车车载视频监控、物流车载监控、油品运输车载监控、警车车载视…

数据结构—图(上)

文章目录 12.图(上)(1).图的基本概念#1.图的基本定义#2.边的分类#3.数据结构的一些规定#4.子图#5.完全图#6.路径#7.连通性和连通分量#8.度 (2).图的存储方式#1.邻接矩阵#2.邻接表 (3).图的遍历#1.深度优先搜索(Depth First Search)i.走个迷宫ii.DFS的思想iii.代码实现 #2.广度优…

LeetCode-无重复字符的最长子串(3)

题目描述&#xff1a; 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 代码&#xff1a; class Solution {public int lengthOfLongestSubstring(String s) {Set<Character> occnew HashSet<Character>();int lens.length();int…

Yolov5/8的小程序部署前后端实现

Yolov5/8的小程序部署前后端实现 导语本机配置硬件环境配置 前端实现后端实现总结参考文献 导语 毕设的题目与Yolo系列的图像识别相关&#xff0c;通过搜查了很多资料和实践最后完成&#xff0c;看到某些平台上居然卖300&#xff0c;觉得很离谱&#xff0c;所以决定把代码开源…

Springcloud alibab和dubbo有什么区别?

Spring Cloud Alibaba 和 Dubbo 都是为了简化企业级应用开发而生的框架&#xff0c;尤其是在分布式系统和微服务架构的背景下。 虽然他们在某些功能上有重叠&#xff0c;但各有侧重点和使用场景。 微服务架构图 首先介绍一下 Spring Cloud Alibaba&#xff1a; Spring Cloud …

Fiddler抓取https原理?

首先fiddler截获客户端浏览器发送给服务器的https请求&#xff0c; 此时还未建立握手。 第一步&#xff0c; fiddler向服务器发送请求进行握手&#xff0c; 获取到服务器的CA证书&#xff0c; 用根证书公钥进行解密&#xff0c; 验证服务器数据签名&#xff0c; 获取到服务器C…

数据结构学习 jz34 二叉树中和为某一值的路径

关键词&#xff1a;回溯 二叉树 前序遍历 路径记录 因为我没有仔细接触过二叉树的遍历过程&#xff0c;所以我是懵懵懂懂按照dfs的方法写的。没想到写对了&#xff0c;看了解答发现这叫做二叉树的前序遍历。用时29min。 这让我明白了前序遍历和dfs原来是有相同之处的。&#…

Local server not started, start with 报错python -m weditor

一、python -m weditor 如图报错 Local server not started, start with 报错 二、解决方案 右上角选择新的无痕窗口下&#xff0c;然后打开 http://localhost:17310/ 即可

PCIe 6.0生态业内进展分析总结-2

3.PCIe 6.0协议分析仪 (1)Keysight Keysight是德科技在2023年6月份对外宣布&#xff0c;第一款支持PCIe 6.0协议验证调试工具。 Keysight PCIe 6.0架构解决方案具备以下特点&#xff1a; 分析PCIe 6.0技术设计的数据链路/事务层 支持所有PCIe技术速率——从2.5 GT/s至64 GT/…

实验笔记之——基于COLMAP的Instant-NGP与3D Gaussian Splatting的对比

之前博客进行了COLMAP在服务器下的测试 实验笔记之——Linux实现COLMAP-CSDN博客文章浏览阅读794次&#xff0c;点赞24次&#xff0c;收藏6次。学习笔记之——NeRF SLAM&#xff08;基于神经辐射场的SLAM&#xff09;-CSDN博客NeRF 所做的任务是 Novel View Synthesis&#xf…

《PySpark大数据分析实战》-25.数据可视化图表Matplotlib介绍

&#x1f4cb; 博主简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是wux_labs。&#x1f61c; 热衷于各种主流技术&#xff0c;热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员&#xff08;PCTA&#xff09;、TiDB数据库专家&#xff08;PCTP…

2024-01-04 用llama.cpp部署本地llama2-7b大模型

点击 <C 语言编程核心突破> 快速C语言入门 用llama.cpp部署本地llama2-7b大模型 前言一、下载llama.cpp以及llama2-7B模型文件二、具体调用总结 使用协议: License to use Creative Commons Zero - CC0 该图片个人及商用免费&#xff0c;无需显示归属&#xff0c;但如果…

阿里通义千问「全民舞王」,一张照片就能跳《科目三》,刷爆朋友圈

这两天看朋友圈、网上都在发这种跳舞的视频。只要上传一张全身照&#xff0c;就可以生成各种跳舞的视频。 比如前段时间火爆海底捞的《科目三》&#xff0c;还有《DJ慢摇》、《鬼步舞》、《兔子舞》、甚至还有咱《秧歌舞》。 先来一睹为快&#xff01; 阿里通义千问「全民舞王…

虚拟机(克隆)导入/导出镜像(OVAOVF)

一.了解虚拟化和 UEFI 虚拟化是一种技术&#xff0c;通过在物理硬件上创建虚拟的计算环境&#xff0c;使得多个操作系统和应用程序可以在同一台计算机上同时运行。虚拟机是在这个虚拟化环境中运行的实例&#xff0c;它们需要被赋予操作系统和固件等系统软件来进行运行。UEFI&a…

Python+selenium+chromedriver实现爬虫示例代码

下载好所需程序 1.Selenium简介 Selenium是一个用于Web应用程序测试的工具&#xff0c;直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。 2.Selenium安装 方法一&#xff1a;在Windows命令行&#xff08;cmd&#xff09;输入pip install selenium即可自动安装&am…