从源码角度分析 WeakHashMap 垃圾回收原理

本文解析了WeakHashMap的工作原理,包括如何利用弱引用实现键值对的自动垃圾回收,并探讨了WeakHashMap内部Entry的具体实现及ReferenceQueue在回收过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍
WeakHashMap自然联想到的是HashMap。确实,WeakHashMap与HashMap一样是个散列表,存储内容也是键值对。

这里与HashMap类似的功能就不展开了,本文重点关注在WeakHashMap是如何做到回收数据?

垃圾回收原理
谈WeakHashMap回收原理得从WeakReference(弱引用)说起。

大家都知道GC回收对象前提是,从根集出发的引用中没有有效引用指向该对象,则该对象就可以被回收。

这里的有效引用并不包含WeakReference,虽然弱引用可以用来访问对象,但进行垃圾回收时弱引用并不会被考虑在内,仅有弱引用指向的对象仍然会被GC回收。

那WeakHashMap是如何跟WeakReference关联起来的呢?

我们一起看看实现的code吧。

/**

* The entries in this hash table extend WeakReference, using its main ref

* field as the key.

*/

private static class Entry<K,V> extends WeakReference implements Map.Entry<K,V> {

   V value;

   int hash;

   Entry<K,V> next;



   /**

    * Creates new entry.

    */

   Entry(Object key, V value,

         ReferenceQueue<Object> queue,

         int hash, Entry<K,V> next) {

       super(key, queue);

       this.value = value;

       this.hash  = hash;

       this.next  = next;

   }

大家都知道HashMap实现里面有个Entry数组,WeakHashMap也一样也有一个Entry数组,但是此Entry与彼Entry有些不一样。

WeakHashMap的Entry是继承WeakReference,这样一来,整个Entry就是一个WeakReference。

再来看看Entry的构造方法,调用了super(key, queue),也就是调用了这个构造方法

public class WeakReference extends Reference {

/**

* Creates a new weak reference that refers to the given object.  The new

* reference is not registered with any queue.

*

* @param referent object the new weak reference will refer to

*/

public WeakReference(T referent) {

   super(referent);

}

/**

* Creates a new weak reference that refers to the given object and is

* registered with the given queue.

*

* @param referent object the new weak reference will refer to

* @param q the queue with which the reference is to be registered,

*          or null if registration is not required

*/

public WeakReference(T referent, ReferenceQueue<? super T> q) {

   super(referent, q);

}

}

有两个参数,一个key,一个是queue,这个key就是WeakHashMap中存储的key值,这个queue是WeakHashMap中创建的ReferenceQueue。

// Reference queue for cleared WeakEntries
private final ReferenceQueue queue = new ReferenceQueue<>();
那这个ReferenceQueue是干嘛的呢?

了解GC的朋友可能知道,当GC某个对象时,如果有此对象上还有弱引用与其关联,会将WeakReference对象与Reference类的pending引用关联起来,然后由Reference Handler线程将该插入ReferenceQueue队列。

也就是说当Entry中的key被GC时,会将Entry放入到ReferenceQueue中,WeakHashMap就能个通过ReferenceQueue中的Entry了解到哪些key已经被GC,或者即将马上被GC,起到了通知的作用。

了解了以上信息后,我们再看下面这段代码:

/**

* Expunges stale entries from the table.

*/

private void expungeStaleEntries() {

   for (Object x; (x = queue.poll()) != null; ) {

       synchronized (queue) {

           @SuppressWarnings("unchecked")

              Entry<K,V> e = (Entry<K,V>) x;

           int i = indexFor(e.hash, table.length);



           Entry<K,V> prev = table[i];

           Entry<K,V> p = prev;

           while (p != null) {

               Entry<K,V> next = p.next;

               if (p == e) {

                   if (prev == e)

                       table[i] = next;

                   else

                       prev.next = next;

                   // Must not null out e.next;

                   // stale entries may be in use by a HashIterator

                   e.value = null; // Help GC

                   size--;

                   break;

               }

               prev = p;

               p = next;

           }

       }

   }

}

这段代码就是WeakHashMap用来处理ReferenceQueue中被GC的key所关联的Entry相关数据。

通过从queue中poll出相关的Entry,然后去WeakHashMap的entry数组中找到索引,然后从对应的链中去掉相关的Entry,最后将value赋值为空(Help GC),到这里就完成了相关数据的清理。

但是谁来触发expungeStaleEntries方法呢?有多个方法都可以触发,如put、get、remove、size等方法都能够触发相关的逻辑。

误区
是不是使用了WeakHashMap就一定没有问题了呢?

当然不是,如果没有触发expungeStaleEntries这个方法依然会导致内存泄漏。

比如初始化好WeakHashMap中相关数据后,一直不调用put、get、remove、size等相关方法,也是不能够正常回收的。(put、get、remove、size等相关方法主要是调用了getTable()方法进行调用expungeStaleEntries方法)

### RT-DETRv3 网络结构分析 RT-DETRv3 是一种基于 Transformer 的实时端到端目标检测算法,其核心在于通过引入分层密集正监督方法以及一系列创新性的训练策略,解决了传统 DETR 模型收敛慢和解码器训练不足的问题。以下是 RT-DETRv3 的主要网络结构特点: #### 1. **基于 CNN 的辅助分支** 为了增强编码器的特征表示能力,RT-DETRv3 引入了一个基于卷积神经网络 (CNN) 的辅助分支[^3]。这一分支提供了密集的监督信号,能够与原始解码器协同工作,从而提升整体性能。 ```python class AuxiliaryBranch(nn.Module): def __init__(self, in_channels, out_channels): super(AuxiliaryBranch, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1) self.bn = nn.BatchNorm2d(out_channels) def forward(self, x): return F.relu(self.bn(self.conv(x))) ``` 此部分的设计灵感来源于传统的 CNN 架构,例如 YOLO 系列中的 CSPNet 和 PAN 结构[^2],这些技术被用来优化特征提取效率并减少计算开销。 --- #### 2. **自注意力扰动学习策略** 为解决解码器训练不足的问题,RT-DETRv3 提出了一种名为 *self-att 扰动* 的新学习策略。这种策略通过对多个查询组中阳性样本的标签分配进行多样化处理,有效增加了阳例的数量,进而提高了模型的学习能力和泛化性能。 具体实现方式是在训练过程中动态调整注意力权重分布,确保更多的高质量查询可以与真实标注 (Ground Truth) 进行匹配。 --- #### 3. **共享权重解编码器分支** 除了上述改进外,RT-DETRv3 还引入了一个共享权重的解编码器分支,专门用于提供密集的正向监督信号。这一设计不仅简化了模型架构,还显著降低了参数量和推理时间,使其更适合实时应用需求。 ```python class SharedDecoderEncoder(nn.Module): def __init__(self, d_model, nhead, num_layers): super(SharedDecoderEncoder, self).__init__() decoder_layer = nn.TransformerDecoderLayer(d_model=d_model, nhead=nhead) self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_layers) def forward(self, tgt, memory): return self.decoder(tgt=tgt, memory=memory) ``` 通过这种方式,RT-DETRv3 实现了高效的目标检测流程,在保持高精度的同时大幅缩短了推理延迟。 --- #### 4. **与其他模型的关系** 值得一提的是,RT-DETRv3 并未完全抛弃经典的 CNN 技术,而是将其与 Transformer 结合起来形成混合架构[^4]。例如,它采用了 YOLO 系列中的 RepNCSP 模块替代冗余的多尺度自注意力层,从而减少了不必要的计算负担。 此外,RT-DETRv3 还借鉴了 DETR 的一对一匹配策略,并在此基础上进行了优化,进一步提升了小目标检测的能力。 --- ### 总结 综上所述,RT-DETRv3 的网络结构主要包括以下几个关键组件:基于 CNN 的辅助分支、自注意力扰动学习策略、共享权重解编码器分支以及混合编码器设计。这些技术创新共同推动了实时目标检测领域的发展,使其在复杂场景下的表现更加出色。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值