BufferedReader的cb缓冲区是堆内char[]数组,默认8192长度(16KB),由JVM垃圾回收器管理,每实例独占一份,监控需关注char[]实例数量与老年代晋升趋势,避免因未关闭导致内存堆积。

BufferedReader 的 cb 字符缓冲区(即内部 char[] 数组)属于堆内内存,由 JVM 垃圾回收器统一管理。它不涉及堆外内存(如 DirectByteBuffer),因此其生命周期完全遵循 Java 对象的 GC 规则:只要 BufferedReader 实例本身被回收,其持有的 cb 数组也会一并成为可回收对象。
cb 缓冲区如何影响内存监控
-
cb是一个普通char[],默认长度 8192 → 占用8192 × 2 = 16384字节(16 KB)堆内存 - 若显式指定更大缓冲区(如 65536),则数组大小为
65536 × 2 = 131072字节(128 KB) - 每个活跃的
BufferedReader实例都会独占一份cb,不会共享 - 多线程中若每个线程新建一个
BufferedReader,则每份cb都计入该线程所属堆空间
监控时需注意:
- 它体现为 堆内存中普通 char[] 对象,可通过 MAT、JFR 或 JMX 查看
char[]实例数量与总大小 - 不会出现在“Direct Memory”或“Metaspace”等非堆区域中
-
Runtime.freeMemory()/usedMemory()可间接反映其存在,但无法单独剥离cb的占用量
如何定位 cb 缓冲区的内存开销
✅ 使用 JMX 监控
java.lang:type=MemoryPool,name=PS Old Gen和PS Eden Space中char[]的分布-
✅ 启用 JVM 参数
-XX:+PrintGCDetails -Xloggc:gc.log,观察 GC 日志中char[]是否频繁进入老年代(说明BufferedReader生命周期过长)立即学习“Java免费学习笔记(深入)”;
Alibabacloud Sdk Client Initialization For Java下载在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
✅ 用
jmap -histo <pid>查看运行时char[]实例数和总容量(示例输出):num #instances #bytes class name 1: 42876 1372032 [C ← 大量 char[]
若该行数值异常高,且与
BufferedReader创建频率吻合,即提示缓冲区对象堆积 ✅ 在压力测试中对比:关闭自动关闭(如未调用
close())→BufferedReader泄漏 →cb数组持续驻留堆中 →char[]实例数缓慢上升
避免 cb 缓冲区引发内存问题的关键做法
- 显式关闭
BufferedReader:try-with-resources最可靠,确保close()被调用,释放对cb的引用 - 避免长期持有
BufferedReader实例:不要将其设为静态字段或缓存复用(除非线程安全且明确生命周期) - 不盲目扩大缓冲区:64KB 的
cb单实例就占 128KB 堆内存;100 个并发 reader → 额外占用 12.8MB,易推高 Minor GC 频率 - 注意嵌套流包装:
new BufferedReader(new InputStreamReader(is, "UTF-8"))中,InputStreamReader也有自己的缓冲(cb是BufferedReader的,InputStreamReader内部用byte[]),二者内存开销叠加
它会不会触发 Full GC?
一般不会仅因 cb 引发 Full GC。
但若大量 BufferedReader 未及时关闭,导致 char[] 在年轻代反复晋升至老年代,最终填满老年代,就会触发 Full GC。
这种情况在日志采集、批处理等场景较常见——例如每条请求都 new 一个 BufferedReader 读配置,却忘记 close。
cb 是典型的“小而多”的堆内存消耗点,不显眼但可累积。监控重点不在单个数组,而在它的实例数量趋势与存活时间。

















