ZSTD 内存泄漏问题
优质博文:IT-BLOG-CN
Zstandard(简称zstd)是一种无损压缩算法,由Facebook开发并开源。它旨在提供高压缩比和高解压速度的平衡,适用于多种数据压缩需求。
特点
【1】高压缩比: zstd能够在保持较高压缩比的同时,提供比其他压缩算法更快的压缩和解压速度。
【2】快速解压: 解压速度非常快,适合需要高效解压的应用场景。
【3】可调压缩级别: zstd支持多种压缩级别,从快速压缩到高压缩比,可以根据具体需求进行调整。
【4】流压缩: 支持流式压缩和解压,适合处理大文件或数据流。
【5】多线程支持: zstd支持多线程压缩,能够充分利用多核处理器的性能。
用途
【1】数据存储: 用于压缩存储在磁盘上的数据,以减少存储空间占用。
【2】数据传输: 在网络传输中使用zstd压缩数据,可以减少传输时间和带宽消耗。
【3】日志压缩: 用于压缩日志文件,减少日志存储空间。
【4】数据库: 一些数据库系统使用zstd来压缩数据页,提升存储效率。
【5】文件系统: 某些文件系统支持zstd压缩,以提高存储效率。
示例代码:以下是一个简单的Java示例,演示如何使用zstd进行压缩和解压:
import com.github.luben.zstd.Zstd;
import java.nio.charset.StandardCharsets;public class ZstdExample {public static void main(String[] args) {String originalString = "This is a string to be compressed using zstd!";byte[] originalData = originalString.getBytes(StandardCharsets.UTF_8);// 压缩数据byte[] compressedData = Zstd.compress(originalData);// 解压数据byte[] decompressedData = Zstd.decompress(compressedData, originalData.length);String decompressedString = new String(decompressedData, StandardCharsets.UTF_8);System.out.println("Original: " + originalString);System.out.println("Compressed size: " + compressedData.length);System.out.println("Decompressed: " + decompressedString);}
}
我们在使用zstd组件时发现有一个问题,容易造成内存泄露,大家如有使用或即将使用时要注意下,具体分析如下:
大家能从使用代码上看出问题来吗?看着非常正常。
try (ByteArrayInputstream byteInputstream = new ByteArrayInputstream(obj. getBytes(encoding));ByteArrayoutputstream byteOutputstream new ByteArrayoutputstream()Zstdoutputstream zstdoutputstream = new Zstdoutputstream(byteoutputstream))(byte[] buffer . new byte[CompressConstant.DEFAULT_SIZE_512];int count;while((count= byteInputStream. read(buffer, 0, CompressConstant. DEFAULT SIZE 512))1=-1){zstdoutputstream.write(buffer, , count);}zstdoutputStream.flush();zstdoutputStream.close();
Zstd原码, 重写了finalize,这就是问题根源。
package com.github.luben.zstd;
import java.io.Outputstream;
import java.io.FilterOutputStream;
import java.io. IOException;
import com.github.luben.zstd.util.Native;public class Zstdoutputstream extends Filteroutputstream(static{}/** Opaque pointer to Zstd context object */private long stream;private long srcPos - 0;private long dstPos = 0;private byte[] dst = null;private boolean isclosed.false;private static final int dstSize =(int) recommendedCOutSize();private boolean closeFrameonFlush;private boolean useChecksum;private boolean frameClosed . true;private int level;private byte[] dict = null;private ZstdDictCompress fastDict . null;/* JNI methods */private static native long recommendedcoutsize();private static native long createcstream();private static native int freeCStream(long ctx);private native int initCStream(long ctx, int level, int checksum);private native int initCStreamithDict(long ctx, byte[] dict, int dict_size, int level, int checksum);private native int initCStreamwithFastDict(long ctx, ZstdDictCompress dict, int checksum);private native int compressstream(long ctx, byte[] dst, int dst_size, byte[] src, int src_size);private native int flushStream(long ctx, byte[] dst, int dst_size);private native int endStream(long ctx, byte[] dst, int dst_size);/* The constuctor */public Zstdoutputstream(Outputstream outstream, int level, boolean closeFrameOnFlush, boolean useChecksum) throws IOException(}public synchronized void write(byte[] src, int offset, int len) throws IOException (}public void write(int i) throws IOException(}/***Flushes the output*/public synchronized void flush() throws IOException {}public synchronized void close() throws IOException {}@overrideprotected void finalize() throws Throwable(close();}
咱们来了解下finalize:
finalize是Object对象里的一个方法,它最大的一个特点是执行时机不可预知。实现了object的finalize方法的类,在创建时会新建一个FinalizerReference,这个对象是强引用类型,重写finallize的对象如果没有被其它对象引用时,执行GC不会马上被清除掉,而是放入到一个静态队列中,有一个守护线程专门去处理这个队列,因为守护线程的优先级比较低,运行的时间少,如果在短时间内创建较多或较大对象时,无论怎么调用GC都无用,只能等到守护线程从队列中取出finalize方法,FinalizerReference才能被回收。
Object.finalize方法是Java中定义在java.lang.Object类中的一个方法。它的主要作用是在对象被垃圾回收器回收之前进行一些清理操作。具体来说,finalize方法允许开发者在对象被销毁之前执行一些必要的清理工作,比如释放资源(文件、网络连接等)。
作用:
资源释放:在对象被垃圾回收前释放系统资源,如关闭文件、网络连接等。
清理操作:执行一些清理工作,确保对象的状态一致性。
优点
资源管理:在某些情况下,finalize方法可以用来确保资源被正确释放,避免资源泄漏。
自动调用:在垃圾回收时自动调用,无需手动触发。
缺点
不确定性:finalize方法的调用时间是不确定的,垃圾回收器何时调用finalize方法是不可预测的,这可能导致资源长时间未被释放。
性能开销:使用finalize方法会增加垃圾回收的开销,影响性能。
复杂性: finalize方法容易引入复杂的错误和难以调试的问题,因为它是在垃圾回收的过程中异步调用的。
替代方案: Java 7引入了try-with-resources语法和AutoCloseable接口,这些提供了更好的资源管理方式,通常不需要依赖finalize方法。
实际使用
由于上述缺点,finalize方法在实际开发中已经很少被使用。现代Java开发更倾向于使用try-with-resources语法和AutoCloseable接口来管理资源。例如:
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {// 读取文件内容
} catch (IOException e) {e.printStackTrace();
}
// 这里BufferedReader会自动关闭,无需依赖finalize
看下Finalizer类的原码:
final class Finalizer extends FinalReference<Object> {
/* Package-private; must be in
same package as the Reference
class */private static ReferenceQueue<Object> queue = new ReferenceQueue<>();private static Finalizer unfinalized = null,private static final Object lock = new Object();
private Finalizer(Object finalizee){super(finalizee, queue);add();
}
/* Invoked by VM */
static void register(Object finalizee) { new Finalizer(finalizee); }
static {ThreadGrouptg=Thread.currentThread().getThreadGroup();for (ThreadGroup tgn = tg;tgn != null;tg = tgn, tgn = tg.getParent());Thread finalizer = new FinalizerThread(tg);___finalizer.setPriority(Thread.MAX PRIORITY - 2);finalizer.setDaemon(true);|finalizer.start();
}
private static class FinalizerThread extends Thread {private volatile boolean running;FinalizerThread(ThreadGroup g){super(g, name: "Finalizer");}public void run() {if(running)return;// Finalizer thread starts before System.initializeSystemClass// is called. Wait until JavaLangAccess is availablewhile(!VM.isBooted()){// delay until VM completes initialization try {VM.awaitBooted();} catch (InterruptedException x){// ignore and continue}}final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();running = true;for(;;){try {Finalizer f = (Finalizer)queue.remove();_f.runFinalizer(jla);} catch(InterruptedException x){// ignore and continue}
}
看下重写了finalize方法的效果,因为我们的对象比较大且请求次数多,所以发上生产就能立马见效。

Dump的结果:

解决方法有两个:
【1】直接用Zstd的compress(byte[] src),decompress(byte[] src, int originalSize);
【2】写一个类继承ZstdOutputStream,重载finalize,方法内置空。
大家在写代码时,尽量不要重写object的finalize.
相关文章:
ZSTD 内存泄漏问题
优质博文:IT-BLOG-CN Zstandard(简称zstd)是一种无损压缩算法,由Facebook开发并开源。它旨在提供高压缩比和高解压速度的平衡,适用于多种数据压缩需求。 特点 【1】高压缩比: zstd能够在保持较高压缩比的…...
c# npoi操作excel
今天在弄使用npoi对excel表的操作,遇到个问题就是使用workbook通过filestream打开后,让后workbook.write(filestream)居然报文件流关闭了,无法写入,弄了好久都不行,最后通过写2个excel文件来解决,现在看来我…...
十二:HTTP错误响应码:理解与应对
在现代网络技术中,HTTP(超文本传输协议)是浏览器与服务器之间沟通的基础。每当我们访问网站或发送请求,HTTP会返回一个响应码,这些代码不仅可以表示成功,还可以指示各种问题。本文将以HTTP错误响应码为主题,探讨其含义、常见类型及应对措施。 1. 400 Bad Request - 请求…...
Rust学习(六):函数式编程
Rust学习(六):函数式编程 我们在前一篇博客中已经介绍了如何通过trait和impl实现Rust的面向对象编程,但是Rust本身实际上并不提倡通过类来解决问题。Rust推崇的是函数式编程,强调将函数作为参数值或者其他函数的返回值…...
使用 Vue 和 Create-Vue 构建工程化前端项目
目录 前言1. 工程化的意义与 Vue 的生态支持2. 搭建 Vue 工程化项目2.1 环境准备2.2 使用 create-vue 创建项目2.2.1 初始化项目2.2.2 安装依赖2.2.3 本地运行 3. Vue 项目的目录结构解析4. Vue 开发流程详解4.1 项目入口与根组件4.1.1 main.js 的作用4.1.2 App.vue 的结构 4.2…...
opencv图片明暗度判断方法
OpenCV 的LAB 颜色空间(也称为 CIELAB)是一种颜色对手的颜色模型,它旨在模仿人类的色彩感知。LAB 颜色空间由三个分量组成: L: 亮度分量 (Lightness),范围从 0(黑色)到 100(白色&…...
QT6学习第三天
QT6学习第三天 第一个Widgets项目创建项目项目界面简单介绍编译文件介绍 我在第一天中将重点标了颜色,后边我把一些简单的东西都不写了,写了的都是实际用的东西,就不标颜色了。 第一个Widgets项目 首先我们创建一个widgets项目,…...
计算机网络-MSTP基础实验一(单域多实例)
前面我们已经大致了解了MSTP的基本概念和工作原理,但是我自己也觉得MSTP的理论很复杂不结合实验是很难搞懂的,今天来做一个配套的小实验以及一些配置命令。 一、网络拓扑 单域多实例拓扑 基本需求:SW1为VLAN10的网关,SW2为VLAN20的…...
React合成事件及其核心思想详解
相关联Javascript知识 1.JavaScript 的事件流 事件流是 JavaScript 处理事件的机制,它描述了事件从发生到被处理的过程。事件流主要包括两个阶段:捕获阶段和冒泡阶段。在捕获阶段,事件从文档的根元素开始,逐层向下传播到目标元素&…...
Datawhale模型减肥秘籍Tasking之模型量化
Datawhale模型减肥秘籍Tasking之模型量化 什么是量化?为什么量化?量化基本方法基于k-means的量化线性量化 训练后量化量化粒度动态量化参数的计算 ( Cliping )指数移动平均(EMA)Min-MaxKL 量化均方误差(MSE)…...
在云服务器搭建 Docker
操作场景 本文档介绍如何在腾讯云云服务器上搭建和使用 Docker。本文适用于熟悉 Linux 操作系统,刚开始使用腾讯云云服务器的开发者。如需了解更多关于 Docker 相关信息,请参见 Docker 官方。 说明: Windows Subsystem for Linuxÿ…...
Redis 的代理类注入失败,连不上 redis
在测试 redis 是否成功连接时,发现 bean 没有被创建成功,导致报错 根据报错提示,需要我们添加依赖: <dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>&l…...
版本控制【Git Bash】【Gitee】
目录 一、什么是版本控制? 二、版本控制的种类: 1、本地版本控制 2、集中版本控制 3、分布式版本控制 三、下载Git Bash 四、Git Bash 配置 五、Git Bash使用 1、切换目录:cd 2.查看当前文件路径:pwd 3.列出当前目录下文件…...
Neo4j Desktop 和 Neo4j Community Edition 区别
Neo4j Desktop 和 Neo4j Community Edition 的主要区别在于它们的用途、功能以及安装和管理方式。以下是这两者的详细对比: 1. Neo4j Desktop Neo4j Desktop 是一个图形化的桌面应用程序,主要为开发人员和个人使用提供了一个便捷的环境来安装、管理和运…...
使用uniapp开发微信小程序使用uni_modules导致主包文件过大,无法发布的解决方法
在使用uniapp开发微信小程序时候,过多的引入uni_modules的组件库,会导致主包文件过大,导致无法上传微信小程序,主包要求大小不超过1.5MB.分包大小每个不能超过2M。 解决方法:分包。 1.对每个除了主页面navbar的页面进…...
HarmonyOS NEXT应用元服务开发Intents Kit(意图框架服务)事件推荐开发者测试
意图框架向开发者提供真机测试能力,即开发者可连接设备进行调测。开发者完成代码开发之后,功能正式上架应用市场前,可以在HarmonyOS NEXT设备上面进行自验证,打磨体验。真机测试分为三个步骤:基础信息提供,…...
GD32F103 实践-- MCU编译运行
编译 打开固件库示例工程:在SDK路径下找到固件库示例工程,路径通常是SDK\GD32F10x_Firmware_Library_Template\Keil5_project\Project 选择芯片型号:根据你的MCU型号选择,例如GD32F103RCT6 修改宏定义:根据MCU型号修…...
SQL复杂数据类型处理
背景 数据处理中,经常碰到复杂数据类型,需要将他们进行解析才能利用。 复杂数据类型 1、MAP结构转为列 WITH tmp AS ( SELECT {"Users":{"4418":{"UserId":4418,"Score":0,"IsStudent":true},&q…...
ROS第九梯:ROS+VSCode+Python+C++自定义消息发布和订阅
首先,Python版本的ROS项目和C++版本的ROS项目前期创建功能包的步骤基本一致,具体可参考第二章。 费一步:新建msg文件 在功能包(data_input)目录下创建一个msg文件夹,并在msg文件夹下创建一个名为Box的msg文件,具体如下图所示: 该msg文件为一个用于描述3D Box的文件,…...
【Linux】指令 + 压缩与解压
Linux 一.Linux基本指令1.grep2.zip和unzip1.Linux中的压缩文件发送Windows中2.Linux中接收Windows中压缩文件 3.tar(重要)1.Linux与Linux互传压缩文件 4.bc5.uname 二.Linux相关知识点1.Linux常用热键2.关机操作 一.Linux基本指令 1.grep 行文本过滤工…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
