JVM 学习(2)—简单理解强、软、弱、虚 Java 四大引用

news/2024/4/24 23:59:01/文章来源:https://blog.csdn.net/qq_35971258/article/details/129237991

一、Java 引用概述

Java 中出现四种引用是为了更加灵活地管理对象的生命周期,以便在不同场景下灵活地处理对象的回收问题。不同类型的引用在垃圾回收时的处理方式不同,可以用来实现不同的垃圾回收策略。Java 目前将其分成四类,类图如下:

在这里插入图片描述

Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

    @Deprecated(since="9")protected void finalize() throws Throwable { }
}

传统的 finalize() 方法在 Java 9 中已经被标记为废弃(deprecated),而且在 Java 11 中已经被删除(推荐使用 Cleaner是 Java 新一代的内存回收处理机制)。这是因为 finalize() 方法存在许多问题,包括但不限于以下几点:

  1. finalize() 方法并不能保证被及时地调用,这可能会导致内存泄漏等问题。
  2. finalize() 方法的执行时机是不确定的,可能会导致程序的不可预测行为。
  3. finalize() 方法是被 JVM 调用,手动调用容易出错,不够灵活。

=>Cleaner 的执行过程,如下:

在 JDK9 中,Java 提供了一种新的机制来代替传统的 finalize() 方法来清理对象,就是 Cleaner。Cleaner 是一个 Java 类,用于注册需要进行清理的对象以及相关的清理方法。它使用了本地内存技术,可以在 Java 对象释放后及时进行清理。

当一个 Java 对象不再被引用时,其所占用的内存并不会立即释放,而是会被标记为“可回收”状态。JVM 会在后台开启一个线程,定期扫描这些“可回收”对象,清理其中已经没有引用的对象。Cleaner 就是在这个扫描过程中对于对象的清理操作。

使用 Cleaner 机制时,开发人员需要创建一个 Cleaner 对象,并使用该对象对需要清理的对象进行注册,同时定义一个清理方法。当被注册的对象被回收时,JVM 会在后台的扫描过程中调用注册的清理方法,对对象进行清理操作。相较于传统的 finalize() 方法,Cleaner 机制的清理操作更加灵活,可以在多种情况下触发,并且不会受到 finalize() 方法的不稳定性的影响。

下面是一个使用 Cleaner 的例子:

public class Resource implements AutoCloseable {private static final Cleaner cleaner = Cleaner.create();private final Cleaner.Cleanable cleanable;private ByteBuffer buffer;public Resource(int size) {buffer = ByteBuffer.allocate(size);cleanable = cleaner.register(this, new ResourceCleaner(buffer));}@Overridepublic void close() throws Exception {cleanable.clean();}private static class ResourceCleaner implements Runnable {private ByteBuffer buffer;public ResourceCleaner(ByteBuffer buffer) {this.buffer = buffer;}@Overridepublic void run() {System.out.println("Cleaner is cleaning the resource");buffer = null;}}
}

在上面的例子中,Resource 类使用了 Cleaner 来释放资源。Resource 类中的 buffer 对象在实例化时会被分配内存。当使用完 Resource 实例时,需要调用 close() 方法来释放资源。close() 方法调用了 Cleaner.Cleanable 的 clean() 方法来触发资源的释放。同时,ResourceCleaner 类实现了 Runnable 接口,run() 方法被用来进行资源的清理操作。在这个例子中,资源的清理操作是将 buffer 设置为 null。这样,一旦实例被垃圾收集器回收,clean() 方法就会自动被调用,从而释放资源。

  1. 一般来说,实现了 CloseableAutoCloseable 接口的类,在使用完后都需要手动调用 close() 方法来释放资源。但是有些情况下,JVM 会自动调用 close() 方法,比如在 try-with-resources 语句中,当 try 代码块执行完后,JVM会自动调用相应资源的 close() 方法来释放资源,而无需手动调用。但是,如果在 try-with-resources 语句中使用了多个资源,需要注意它们的释放顺序,确保后打开的资源先关闭,以避免可能出现的资源泄露问题。
     
  2. ResourceCleaner 是由 JVM 的垃圾回收器自动触发的,当一个对象不再被引用时,它的 clean() 方法就会被自动调用。具体来说,当垃圾回收器扫描到一个对象时,如果这个对象实现了 Cleaner.Cleanable 接口,那么垃圾回收器会把它注册到一个全局的 ReferenceHandler 队列中,这个队列中的线程会定期触发这些对象的 clean() 方法。这个过程是由 JVM 自动进行的,程序员无需手动触发。

二、强、软、弱、虚引用简单介绍

1、强引用(Reference 默认)

是最常见的引用类型,也是默认的引用类型。当内存不足,JVM 开始垃圾回收,对于强引用的对象,就算是出现 OOM 也不会对该对象进行回收,死都不放。

强引用只要还指向一个对象,就表示对象还活着,垃圾收集器不会碰这些对象。在 Java 最常见的就是把一个对象赋值给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用引用时,它处理可达状态,它不可能被垃圾回收器回收,即使该对象后面永远都不会被使用,JVM 也不会进行回收。因此强引用是造成 Java 内存泄露的主要原因之一。

比如下面这个例子:

class MyObject {public byte[] buff = new byte[1000 * 1000 * 3];@Overrideprotected void finalize() throws Throwable {System.out.println(">>>>>>调用 finalize 清理资源...");}
}
public class ReferenceDemo {public static void main(String[] args) {MyObject myObject = new MyObject()System.out.println("gc before myObject = " + myObject);try {byte[] bytes = new byte[1000 * 1000 * 8];System.gc();} finally {System.out.println("gc after myObject = " + myObject);}}

首先通过 -Xms10m -Xmx10m 命令把 JVM 堆内存修改成 10M 方便测试,然后定义一个类 MyObject 里面分配一个数组占用堆内存 3M 空间,然后再 main() 方法中又分配一个 8M 大小数组,这样加起来肯定超过 10M 堆内存,会 OOM,但是可以手动调用 System.gc 触发垃圾回收,但是这里并不是回收(finalize() 方法肯定不会被调用),因为这里是属于强引用,就算 OOM 也不会被回收。

在 JVM 准备垃圾回收之前会先去调用 finalize() 方法做一些清理工作,所以只需要覆写该方法演示效果(工作中不会这样干),然后手动调用 System.gc() 让他触发 finalize() 方法调用。
垃圾回收线程是一个后台守护线程,定时在回收垃圾,这里提供 System.gc() 方便手动触发 GC 垃圾回收

效果如下:

gc before myObject = main.juc.MyObject@5ebec15
gc after myObject = main.juc.MyObject@5ebec15
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat main.juc.ReferenceDemo.main(ReferenceDemo.java:27)

那么怎么可以让他回收呢?可以用最简单的方式,将强引用直接赋值 null。修改之后的代码如下:

class MyObject {public byte[] buff = new byte[1000 * 1000 * 1];@Overrideprotected void finalize() throws Throwable {System.out.println(">>>>>>调用 finalize 清理资源...");}
}
public class ReferenceDemo {public static void main(String[] args) {MyObject myObject = new MyObject();System.out.println("gc before myObject = " + myObject);try {byte[] bytes = new byte[1000 * 1000 * 7];myObject = null;System.gc();System.out.println(">>>>>>垃圾回收..."+myObject);} finally {System.out.println("gc after myObject = " + myObject);}}
}

输出结果如下:

gc before myObject = main.juc.MyObject@5ebec15
>>>>>>调用 finalize 清理资源...
>>>>>>垃圾回收...null
gc after myObject = nullProcess finished with exit code 0

myObject = null 可以帮助 JVM 进行垃圾回收。

2、软引用(SoftReference 装饰对象)

如果一个对象只具有软引用,则在系统内存不足时,垃圾回收器会尝试回收该对象。这种引用类型通常用于缓存中,以便在内存不足时自动释放缓存,可以通过 SoftReference 类来创建软引用。例子如下:

class MyObject {public byte[] buff = new byte[1000 * 1000 * 3];@Overrideprotected void finalize() throws Throwable {System.out.println(">>>>>>调用 finalize 清理资源...");}
}
public class ReferenceDemo {public static void main(String[] args) {SoftReference<MyObject> softReference = new SoftReference<>(new MyObject());try {System.out.println("gc before myObject = " + softReference.get());byte[] buf = new byte[1000*1000*3];System.gc();Thread.sleep(3000);System.out.println("gc after myObject = " + softReference.get());} finally {System.out.println(">>>>>>内存不够 myObject="+softReference.get());}}
}

首先通过 -Xms10m -Xmx10m 命令把 JVM 堆内存修改成 10M 方便测试,然后把需要标识为软引用的对象通过 SoftReference 关键字进行包装。MyObject 类中首先分配一个数组,数组占堆内存大约 3M 空间,mian() 方法 3M 空间,远远还没有超过 10M 分配内存大小,然后手动调用 gc,效果如下:

gc before myObject = main.juc.MyObject@5ebec15
gc after myObject = main.juc.MyObject@5ebec15
>>>>>>内存不够 myObject=main.juc.MyObject@5ebec15

明显在内存足够的情况下,不会触发 GC 垃圾回收。现在将代码修改成下面这样,代码如下:

class MyObject {public byte[] buff = new byte[1000 * 1000 * 3];@Overrideprotected void finalize() throws Throwable {System.out.println(">>>>>>调用 finalize 清理资源...");}
}
public class ReferenceDemo {public static void main(String[] args) {SoftReference<MyObject> softReference = new SoftReference<>(new MyObject());try {System.out.println("gc before myObject = " + softReference.get());byte[] buf = new byte[1000*1000*7];System.gc();Thread.sleep(3000);System.out.println("gc after myObject = " + softReference.get());} finally {System.out.println(">>>>>>内存不够 myObject="+softReference.get());}}
}

效果如下:

gc before myObject = main.juc.MyObject@5ebec15
gc after myObject = null
>>>>>>内存不够 myObject=null

明显在内存不足时,会触发 GC 垃圾回收,将 SoftReference 引用的内存空间释放,这个就是 SoftReference 引用的好处。内存足,不回收,反之,回收。

3、弱引用( WeakReference 装饰对象)

如果一个对象有弱引用,只要当垃圾回收器扫描到这个对象时,无论内存是否充足,都会回收该对象。弱引用通常用于实现缓存、内存敏感的高速缓存、监视器等功能。可以通过 WeakReference 类来创建弱引用。通过 -Xms10m -Xmx10m 命令把 JVM 堆内存修改成 10M 方便测试。代码如下:

通过 -Xms10m -Xmx10m 命令把 JVM 堆内存修改成 10M 方便测试。

class MyObject {public byte[] buff = new byte[1000 * 1000 * 3];@Overrideprotected void finalize() throws Throwable {System.out.println(">>>>>>调用 finalize 清理资源...");}
}
public class ReferenceDemo {public static void main(String[] args) {WeakReference<MyObject> softReference = new WeakReference<>(new MyObject());try {System.out.println("gc before myObject = " + softReference.get());System.gc();Thread.sleep(3000);System.out.println("gc after myObject = " + softReference.get());} catch (Exception e) {System.out.println(">>>>");} finally {System.out.println(">>>>>>内存不够 myObject="+softReference.get());}}
}

输出结果如下:

gc before myObject = main.juc.MyObject@5ebec15
>>>>>>调用 finalize 清理资源...
gc after myObject = null
>>>>>>内存不够 myObject=null

看到不管内存是否还有,只要 GC 扫描(System.gc() 可以出发 GC 扫描)到就会直接被回收。

补充:通过弱引用举个实际案例如下:

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;public class ImageLoader {private Map<String, WeakReference<Image>> cache = new HashMap<>();public Image loadImage(String filename) {Image image = null;WeakReference<Image> ref = cache.get(filename);if (ref != null) {image = ref.get();}if (image == null) {image = loadImageFromDisk(filename);cache.put(filename, new WeakReference<>(image));}return image;}private Image loadImageFromDisk(String filename) {// load image from diskreturn null;}
}

在这个示例中,ImageLoader 类使用一个 HashMap 来缓存已加载到内存中的图片,每个图片对应一个弱引用。当需要加载图片时,首先从缓存中查找图片是否已经加载到内存中,如果是,则返回弱引用所引用的图片对象;否则,从磁盘中加载图片,并将其添加到缓存中,同时返回图片对象。

由于缓存中的每个图片对象都是弱引用,因此在内存不足时,垃圾回收器会自动回收这些图片对象所占用的内存空间,从而实现内存管理。

补充:ThreadLocal 中为什么需要使用弱引用?

ThreadLocal 使用弱引用是为了防止内存泄漏。由于 ThreadLocalMap 是存在 Thread 中的,如果使用强引用,一旦ThreadLocal 对象被回收,它在 ThreadLocalMap 中对应的 Entry 对象也不会被回收,这样就会导致 Entry 对象中的value对象长时间得不到回收,最终导致内存泄漏。
使用弱引用可以让 ThreadLocal 对象被回收后,Entry 对象中的 value 对象在下一次 ThreadLocalMap 的操作时被顺便回收,从而避免了内存泄漏的问题。

4、虚引用(PhantomReference 装饰对象)

也称为幽灵引用,如果一个对象只具有虚引用,那么这个对象就和没有引用一样,在任何时候都可能被垃圾回收器回收。虚引用通常用于跟踪对象被垃圾回收器回收的状态,可以通过 PhantomReference 类来创建虚引用。

顾明思义,就是形同虚设,与其他几种引用都不同,虚拟引用并不会决定对象的声明周期。

如果一个对象仅持有虚引用,那么他就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独实用也不能通过虚引用访问对象,虚引用必须和引用队列 ReferenceQueue 一起使用

虚引用的主要作用就是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被 finalize() 以后,可以做某些操作。PhantomReference.get() 方法总是会返回 null,因此无法访问对应的引用对象。比如:在这个对象被垃圾收集器回收的时候收一个系统通知或者做进一步的处理。举个例子:

通过 -Xms10m -Xmx10m 命令把 JVM 堆内存修改成 10M 方便测试。

class MyObject {@Overrideprotected void finalize() throws Throwable {System.out.println(">>>>>>调用 finalize 清理资源...");}
}public class ReferenceDemo {public static void main(String[] args) throws InterruptedException {ReferenceQueue<MyObject> queue = new ReferenceQueue<>();PhantomReference<MyObject> softReference = new PhantomReference<>(new MyObject(), queue);List<byte[]> list = new ArrayList<>();new Thread(() -> {while (true) {try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}list.add(new byte[1000 *  1000  * 1]);System.out.println("softReference.get() = " + softReference.get());}}).start();new Thread(() -> {while (true) {if (queue.poll() != null) {System.out.println(">>>>>>引用队列有值啦...");}}}).start();Thread.sleep(8000);}
}

输出结果如下:

softReference.get() = null
softReference.get() = null
softReference.get() = null
softReference.get() = null
softReference.get() = null
softReference.get() = null
>>>>>>调用 finalize 清理资源...
softReference.get() = null
softReference.get() = null
>>>>>>引用队列有值啦...java.lang.ref.PhantomReference@5c4efc23>>>type=class java.lang.ref.PhantomReference
softReference.get() = nullException: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "Thread-0"
Java HotSpot(TM) 64-Bit Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGINT to handler- the VM may need to be forcibly terminated

上述代码中,通过 PhantomReference 创建出虚引用,并且传入 ReferenceQueue 队列。线程1不断地在堆内存中申请空间,每次 1M 大小,因为虚引用包裹的对象,通过 softReference.get() 都是返回 null。线程1一直这样添加,直到内存不足时,虚引用对象会被放到 ReferenceQueue 队列中,ReferenceQueue 队列可以帮助我们在虚引用对象被回收时及时得到通知,从而进行必要的清理工作。其实就是表示这个虚引用在死之前想要留一些遗言,人类就可以监控到这个引用队列看到谁在死之前还有遗言,去帮他实现一下。

补充:

虚引用(Phantom Reference)是 Java 引用类型中最弱的一种,虚引用对象被GC回收的时候会放入一个由 ReferenceQueue管理的队列中。

虚引用的一个常见用途是管理 DirectByteBuffer 对象,它可以让我们对 DirectByteBuffer 对象的回收时间进行监控,一旦 DirectByteBuffer 对象被GC回收,就可以通知我们进行必要的资源释放操作,比如释放内存映射文件等。

以下是一个使用虚引用管理DirectByteBuffer的简单示例代码:

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.nio.ByteBuffer;public class DirectByteBufferTest {private static final int BUFFER_SIZE = 1024 * 1024;private static final int MAX_BUFFERS = 10;private static final ByteBuffer[] buffers = new ByteBuffer[MAX_BUFFERS];private static final ReferenceQueue<ByteBuffer> queue = new ReferenceQueue<>();static {for (int i = 0; i < MAX_BUFFERS; i++) {buffers[i] = ByteBuffer.allocateDirect(BUFFER_SIZE);new PhantomReference<>(buffers[i], queue);}}public static void main(String[] args) throws InterruptedException {for (int i = 0; i < MAX_BUFFERS; i++) {ByteBuffer buffer = buffers[i];System.out.println("buffer " + i + ": " + buffer);buffers[i] = null;buffer = null;}System.gc();Thread.sleep(1000);Reference<? extends ByteBuffer> ref;while ((ref = queue.poll()) != null) {ByteBuffer buffer = ref.get();System.out.println("buffer " + buffer + " is released");// Release resources here}}
}

该示例程序通过创建10个 DirectByteBuffer 对象并将它们的虚引用对象放入队列中来管理这些 DirectByteBuffer 对象。在程序运行的过程中,首先会打印出10个 DirectByteBuffer 对象的地址,然后将它们的引用全部置为 null,这样它们就可以被GC回收。程序接着调用 System.gc() 来触发一次垃圾回收,然后调用 Thread.sleep() 让程序睡眠1秒钟等待垃圾回收完成。最后程序从 ReferenceQueue 中取出所有被回收的 DirectByteBuffer 对象的虚引用,进行必要的资源释放操作。

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

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

相关文章

mysql一两种索引方式hash和btree

1. Hash索引&#xff1a; Hash 索引结构的特殊性&#xff0c;其检索效率非常高&#xff0c;索引的检索可以一次定位&#xff0c;不像B-Tree 索引需要从根节点到枝节点&#xff0c;最后才能访问到页节点这样多次的IO访问&#xff0c;所以 Hash 索引的查询效率要远高于 B-Tree 索…

信息安全概论之《密码编码学与网络安全----原理与实践(第八版)》

前言&#xff1a;在信息安全概论课程的学习中&#xff0c;参考了《密码编码学与网络安全----原理与实践&#xff08;第八版&#xff09;》一书。以下内容为以课件为主要参考&#xff0c;课本内容与网络资源为辅助参考&#xff0c;学习该课程后作出的总结。 一、信息安全概述 1…

力扣Top100题之两数相加(Java解法)

0 题目描述 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数…

MVCC 当前读 快照读 RC read view RR下事务更新不会丢失

MVCC(multi-version-concurrent-control) MVCC是行锁的一个变种&#xff0c;但MVCC在很多情况下它避免了加锁。不是buffer块&#xff0c;而是buffer中的记录行。 MVCC (Multi-Version Concurrency Control) (注&#xff1a;与MVCC相对的&#xff0c;是基于锁的并发控制&#x…

【无限思维画布】制作思维导图第五步,节点创建与连接,拖拽对齐与双击缩放

正在为无限词典制作单词思维导图功能&#xff0c;实现无限单词导图&#xff0c;无限思维画布。目前制作到第五步&#xff0c;实现节点创建、节点连接、节点拖拽对齐&#xff1a; 节点创建与连接&#xff0c;拖拽对齐Details 第四步&#xff0c;推倒重来。 一开始受vue-mindma…

【Python小程序】这款成语接龙小程序,让小孩儿轻松记住500个成语,在家里常玩,语文直上135,仅此一份,快收藏~(太强大了)

前言 学习路上&#xff0c;那我同行。 哈喽~大家晚上好呀&#xff0c;我是你们的栗子同学。 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移步至CSDN社区或文末公众hao即可免费。 成语接龙是一个传统的文字游戏。很多孩子都喜欢玩。…

Lesson9---回归问题

9.1 机器学习基础 课程回顾 Python语言基础Numpy/Matplotlib/Pandas/Pillow应用TensorFlow2.0 低阶API 即将学习 机器学习、人工神经网络、深度学习、卷积神经网络典型模型的TensorFlow2.0实现 9.1.1 机器学习 机器学习&#xff08;Machine Learning&#xff09;&#xf…

关于C语言中最大公因数的思考

目录 如何去求最大公因数利用枚举法&#xff1a; 如何去求最大公因数利用辗转相除法&#xff1a; 例1&#xff1a;最大公因数使用for循环和if语句 示例2&#xff1a;最大公因数使用while循环和if ... else语句 例3&#xff1a;正负数均为最大公因数 如何去求最大公因数利用…

【2023-02-27】349.两个数组的交集

题目链接&#xff1a;349.两个数组的交集 解题思路&#xff1a;点我 class Solution { public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {unordered_set<int>res_set;unordered_set<int>nums1_set(nums1.beg…

qt-c++进阶1-window、linux下获取本机所有网卡ip信息、根据网卡名获取ip地址。

系列文章目录 例如&#xff1a;第一章 主要是通过qt-c实现获取本机电脑的网卡信息或者是IP信息 文章目录系列文章目录前言一、获取本机网卡IP信息1.1 获取ip地址方法1.2 代码实例总结前言 总结c获取本机网卡信息的方法 第一章&#xff1a;适用于windows操作系统、linux操作系…

Aspose.Slides for .NET 授权须知

Aspose.Slides是一款用于生成&#xff0c;管理和转换PowerPoint幻灯片的本机API&#xff0c;可以使用多种格式&#xff0c;而不需要Microsoft PowerPoint。并且可在任何平台上操作PowerPoint演示文稿。 Aspose.Slides for .NET是一款.NET PowerPoint管理API&#xff0c;用于读…

常用逻辑运算符

逻辑符号表格 逻辑符号含义描述&按位与将数字转成二进制计算&#xff0c;两个位都为1时&#xff0c;结果才为1|或两个位都为0时&#xff0c;结果才为0 &#xff0c;反知任何一个为1结果为1^异或两个位相同为0&#xff0c;不同为1<<左移整体二进位全部左移若干位&…

webrtc音视频通话(一)搭建turn服务器

全球定位&#xff1a;webrtc音视频通话&#xff08;一&#xff09;搭建turn服务器webrtc音视频通话&#xff08;二&#xff09;简单音视频通话webrtc音视频通话&#xff08;三&#xff09;整合websocket在学习webrtc之前呢&#xff0c;需要对websocket有一定基础&#xff0c;如…

腾讯云卖向“有币”区块链

曾经坚决“不涉币”的腾讯云将业务延伸向“有币区块链”。 在首届 Web3 全球峰会“腾讯云Web3构建日”上&#xff0c;腾讯云宣布进军Web3&#xff0c;并公开了与Ankr、Avalanche、Scroll和Sui 四个原生区块链项目的合作&#xff0c;其中前两个项目都发行了加密货币&#xff0c…

比特数据结构与算法(第四章_中_续②)堆解决Topk问题(最小的k个数)

TopK问题介绍&#xff1a;在N个数中找出最大/小的前K个 &#xff08;比如在1000个数中找出最大/小的前10个&#xff09;以前的方法&#xff1a;冒泡排序。时间复杂度&#xff1a; O(N^2)现在找最大的k个数的方法&#xff1a;方法1&#xff1a;堆排序降序&#xff0c;前N个就是最…

使用非对称加密(RSA) 实现前端加密后端解密

数据加密方式有&#xff1a; 单向加密、对称加密、非对称加密、加密盐、散列函数、数字签名。 1、单向加密 单向加密通过对数据进行摘要计算生成密文&#xff0c;密文不可逆推还原。只能加密&#xff0c;不能解密&#xff0c;常用于提取数据的指纹信息以此来验证数据的完整性…

JVM内存溢出与内存泄露

1. 什么是内存溢出? 当前创建的对象的大小大于可用的内存容量大小&#xff0c;发生内存溢出。2. 什么是内存泄露? 该回收的垃圾对象没有被回收&#xff0c;发生了内存泄露&#xff0c;垃圾对象越堆越多&#xff0c; 可用内存越来越少&#xff0c;若可用内存无法存放新的垃圾…

Tcpdump抓包验证zookeeper的心跳机制

一、背景 在分布式系统中&#xff0c;zookeeper可以作为服务注册中心&#xff0c;所有提供服务的节点都可以在zookeeper上面注册&#xff0c;并作为一个node被组织起来&#xff0c;如下图&#xff1a; 在RPC框架中&#xff0c;这些服务提供者就是RPC服务的提供者。zookeeper注…

185、【栈与队列】leetcode ——496. 下一个更大元素 I:单调栈-哈希表(C++版本)

题目描述 原题链接&#xff1a;496. 下一个更大元素 I 解题思路 本题与 739. 每日温度 的区别在于&#xff0c;需要先通过让nums1与nums2判定出为想等元素后&#xff0c;再去找nums2中更大的数。 因此&#xff0c;第一步需要找到想等数&#xff0c;第二步需要找到大于的数。…

c++之引用

目录 引用的概念 引用做函数参数 引用的本质 常引用 引用的概念 在c中新增加了引用的概念&#xff0c;引用可以看作一个已定义变量的别名。 引用的语法&#xff1a;Type &name var; int main() {int a 10;int &b a;printf("b%d\n", b);printf(&quo…