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, 0CompressConstant. 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 - 0private long dstPos = 0private 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
finalizeObject对象里的一个方法,它最大的一个特点是执行时机不可预知。实现了objectfinalize方法的类,在创建时会新建一个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】直接用Zstdcompress(byte[] src),decompress(byte[] src, int originalSize);
【2】写一个类继承ZstdOutputStream,重载finalize,方法内置空。

大家在写代码时,尽量不要重写objectfinalize.

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式硬件电子电路设计(五)LDO低压差线性稳压器全面详解

引言&#xff1a; LDO&#xff08;Low Dropout Regulator&#xff0c;低压差线性稳压器&#xff09;是一种常用的电源管理组件&#xff0c;用于提供稳定的输出电压&#xff0c;同时允许较小的输入电压与输出电压之间的差值。LDO广泛应用于各种电子设备中&#xff0c;特别是在对…

D3基础:绘制圆形、椭圆形、多边形、线、路径、矩形

在D3.js中&#xff0c;可以通过SVG元素来创建各种几何图形。以下是D3.js中常用的几何图形及其简单的创建方法&#xff1a; 1. 圆形 (Circle) 圆形是最基本的形状之一&#xff0c;可以通过<circle>标签来创建。 <!DOCTYPE html> <html> <head><met…

17.100ASK_T113-PRO 配置QT运行环境(三)

前言 1.打开QT,新建项目. 做成以下效果,会QT都没有问题吧 编译输出: /home/book/LED_and_TempHumi/build-LED_and_TempHumi-100ask-Debug LED_and_TempHumi 2.下载程序与测试 设置运行环境 export QT_QPA_PLATFORMlinuxfb 这个地方还需要加字体,不然不会显示字体.

React 实现网页首页设计

目录 页面分解 项目初始化 项目结构 运行项目 页面分解 页面主要元素&#xff1a; Header&#xff08;导航栏&#xff09; 包含网站 logo 和导航菜单。Hero Section&#xff08;主横幅&#xff09; 大背景图片、标题文字、描述文字。Features Section&#xff08;功能展示…

[Go实战]:SSE消息推送

前言 在现代Web开发中&#xff0c;前后端分离已成为主流趋势。为了实现实时数据推送&#xff0c;Server-Sent Events (SSE) 是一种高效且易于实现的技术。本文将介绍如何在Go语言中实现SSE服务端&#xff0c;并在前端使用JavaScript进行集成&#xff0c;实现一个完整的实时数据…

使用OkHttp进行HTTPS请求的Kotlin实现

OkHttp简介 OkHttp是一个高效的HTTP客户端&#xff0c;它支持同步和异步请求&#xff0c;自动处理重试和失败&#xff0c;支持HTTPS&#xff0c;并且可以轻松地与Kotlin协程集成。OkHttp的设计目标是提供最简洁的API&#xff0c;同时保持高性能和低延迟。 为什么选择OkHttp …

【技术解析】Dolphinscheduler实现MapReduce任务的高效管理

MapReduce是一种编程模型&#xff0c;用于处理和生成大数据集&#xff0c;主要用于大规模数据集&#xff08;TB级数据规模&#xff09;的并行运算。本文详细介绍了Dolphinscheduler在MapReduce任务中的应用&#xff0c;包括GenericOptionsParser与args的区别、hadoop jar命令参…

Linux :进程间通信之管道

一、进程间通信 1.1 是什么和为什么 1、进程间通信是什么&#xff1f;&#xff1f; ——>两个或多个进程实现数据层面的交互&#xff0c;但是由于进程独立性的存在&#xff0c;导致通信的成本比较高。 2、既然通信成本高&#xff0c;那为什么还要通信呢&#xff1f;&…

Vue基础(2)_el和data的两种写法

举例&#xff1a; <div id"root"><h1>你好&#xff0c;{{name}}</h1> </div> el和data的2种写法 1.el有2种写法 (1).new Vue时候配置el属性。 // 第一种写法&#xff1a;new Vue时候配置el属性。// 优点&#xff1a;简单、直接new Vue({e…

【汇编语言】数据处理的两个基本问题(二) —— 解密汇编语言:数据长度与寻址方式的综合应用

文章目录 前言1. 指令要处理的数据有多长&#xff1f;1.1 通过寄存器指明数据的尺寸1.1.1 字操作1.1.2 字节操作 1.2 用操作符X ptr指明内存单元的长度1.2.1 访问字单元1.2.2 访问字节单元1.2.3 为什么要用操作符X ptr指明 1.3 其他方法 2. 寻址方式的综合应用2.1 问题背景&…

c++多态(深度刨析)

C系列-----多态 文章目录 C系列-----多态前言一、多态的概念二、多态的定义及实现2.1、多态构成的条件2.1.1、虚函数2.1.2、虚函数的重写 2.2、C11 override 和 final2.3、重载、覆盖(重写)、隐藏(重定义)的对比2.4、抽象类2.5、 接口继承和实现继承 三、多态的原理3.1、虚函数…

FPGA开发技能(9)快速生成约束XDC文件

文章目录 1.从Cadence导出csv约束文件2.python程序将csv导出为xdc文件。3.python生成exe4.exe使用注意事项5.传送门 前言&#xff1a; 作为一名FPGA工程师&#xff0c;通常公司会对该岗位的人有一定的硬件能力的要求&#xff0c;最基础的就是需要依据原理图的设计进行FPGA工程内…

css uniapp背景图宽度固定高度自适应可以重复

page {height: 100%;background-image: url(https://onlinekc.a.hlidc.cn/uploads/20241115/350f94aaf493d05625a7ddbc86c7804e.png);background-repeat: repeat;background-size: contain;} 如果不要重复 把background-repeat: repeat;替换background-repeat: no-repeat;

Stable Diffusion核心网络结构——U-Net

​ &#x1f33a;系列文章推荐&#x1f33a; 扩散模型系列文章正在持续的更新&#xff0c;更新节奏如下&#xff0c;先更新SD模型讲解&#xff0c;再更新相关的微调方法文章&#xff0c;敬请期待&#xff01;&#xff01;&#xff01;&#xff08;本文及其之前的文章均已更新&a…

学习threejs,使用AnimationMixer实现变形动画

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.AnimationMixer 动画…

【Linux】指令 + 重定向操作

Linux基本指令 一.Linux基本指令1.mv&#xff08;重要&#xff09;2.cat3.more和less&#xff08;重要&#xff09;4.head和tail5.date6.cal7.find&#xff08;重要&#xff09; 二.Linux相关知识点1. Linux系统中&#xff1a;一切皆文件2. 重定向操作1. 输出重定向2. 追加重定…

SpringBoot源码解析(四):解析应用参数args

SpringBoot源码系列文章 SpringBoot源码解析(一)&#xff1a;SpringApplication构造方法 SpringBoot源码解析(二)&#xff1a;引导上下文DefaultBootstrapContext SpringBoot源码解析(三)&#xff1a;启动开始阶段 SpringBoot源码解析(四)&#xff1a;解析应用参数args 目录…

Vue3.0 + Ts:动态设置style样式 ts 报错

error TS2322: Type ‘{ width: string; left: string; ‘background-color’: unknown; ‘z-index’: number; }’ is not assignable to type ‘StyleValue’ 在 vue3.0 ts 项目中&#xff0c;动态设置样式报错 在 Vue 3 TypeScript 项目中&#xff0c;当你使用 :style 绑…

跨平台WPF框架Avalonia教程 十六

SelectableTextBlock 可选文本块 SelectableTextBlock 块是一个用于显示文本的标签&#xff0c;允许选择和复制文本。它可以显示多行&#xff0c;并且可以完全控制所使用的字体。 有用的属性​ 您可能最常使用这些属性&#xff1a; 属性描述SelectionStart当前选择的起始字…

【MySQL】库的基础操作入门指南

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;MySQL入门指南&#xff1a;从零开始的数据库之旅 欢迎大家点赞收藏评论&#x1f60a; 目录 ☁创建数据库语法说明&#xff1a; 创建数据库案例 &#x1f308;字符集和校验规则查看系统默认字符集…