弱引用表

简介: 弱引用表

垃圾收集器不能猜测我们认为那些是垃圾。一个典型的例子就是,栈通常由一个数组和一个指向栈顶的索引实现。我们知道,数组的有效部分总是向顶部扩展的,但 Lua 语言却不知道。如果弹出一个元素时只是简单的递减听不索引,那么这个仍然留在数组中的对象对于 Lua 语言来说并不是垃圾。同理,即使是程序不会再用到的、存储在全局变量中的对象,对于 Lua 语言来说也不是垃圾。在这两种情况下,都需要我们的代码将这些对象所在的位置赋值为 nil ,以便这些位置不会锁定可释放的对象。


不过,简单地清除引用可能还不够。在有些情况下,还需要程序和垃圾收集器之间的协作。一个典型的例子是:当我们要保存某些类型(例如:文件)的活跃对象的列表时。这个需求看上去很简单,我们只需要把每个对象插入数组即可;但是,一旦一个对象成为了数组的一部分,它就再也无法被回收了!虽然已经没有任何地方在引用它,但数组依然在引用它。除非我们告诉 Lua 语言数组对该对象的引用不应该阻碍对此对象的回收,否则 Lua 语言本身是无从知晓的。


弱引用表就是这样一种用来专门告诉 Lua 语言一个引用不应该阻止对一个对象回收的机制。所谓弱引用是一种不在垃圾收集器考虑范围内的对象引用。如果对一个对象的所有引用都是弱引用,那么垃圾收集器将会回收这个对象并删除这些弱引用。 Lua 语言通过弱引用表实现弱引用,弱引用表就是元素均为弱引用的表,这意味着如果一个对象只被一个弱引用表持有,那么 Lua 语言最终会回收这个对象。


表由键值对组成,其两者都可以容纳任意类型的对象。在正常情况下,垃圾收集器不会回收一个在可访问的表中作为键或值的对象。也就是说,键和值都是强引用,它们会阻止对其所指向对象的回收。在一个弱引用表中,键和值都可以是弱引用的。这就意味着有三种类型的弱引用表,即具有弱引用键的表、具有弱引用值的表及同时具有弱引用键和值的表。不论是那种类型的弱引用表,只要有一个键或值被回收了,那么对应的整个键值对都会被从表中删除。


一个表是否为弱引用表是有其元表中的 __mode 字段所决定的。当这个字段存在时,其值应为一个字符串

  • 如果这个字符串是"k",那么这个表的键是弱引用的。
  • 如果这个字符串是"v",那么这个表的值是弱引用的。
  • 如果这个字符串是"kv",那么这个表的键和值都是弱引用的。


下面这个示例虽然有些刻意,但演示了弱引用表的基本行为:

a = {}
mt = {__mode = "k"}
setmetatable(a, mt)   -- 现在'a'的键是弱引用的了
key = {}              -- 创建第一个键
a[key] = 1
key = {}              -- 创建第二个键
a[key] = 2
collectgarbage()      -- 强制进行垃圾回收
for k, v in pairs(a) do print(v) end      --> 2


在本例中,第二句赋值 key = {} 覆盖了指向第一个键的索引。调用 collectgarbage 强制垃圾收集器进行一次完整的垃圾收集。由于已经没有指向第一个键的其他引用,因此 Lua 语言会回收这个键并从表中删除对应的元素。然而,由于第二个键仍然被变量 key 所引用,因此 Lua 不会回收它。


注意

只有对象可以从弱引用表中被移除,而像数字和布尔这样的""是不可回收的。例如,我们在表 a 中插入一个数值类型的键,那么垃圾收集器永远不会回收它。当然,如果在一个值为弱引用的弱引用表中,一个数值类型键相关联的值被回收了,那么整个元素都会从这个弱引用表中被删除。


字符串在这里表现了一些细微的差别,虽然从实现的角度看字符串是可回收的,但字符串又与其他的可回收对象不同。其他的对象,例如表和闭包,都是被显式创建的。例如,当 Lua 语言对表达式 {} 求值时会创建一个新表。然而,当对表达式 "a".."b" 求值时, Lua 语言会创建一个新字符串吗?如果当前系统中已有了一个字符串 "ab" 会怎么样? Lua 语言会创建一个新的字符串吗?编译器会在运行程序前先创建这个字符串吗?其实,这些都无关紧要,因为他们都是实现上的细节。从程序员的角度看,字符串是值而不是对象。所以,字符串就像数值和布尔值一样,对于一个字符串类型的键来说,除非它对应的值被回收,否则是不会从弱引用表中被移除的。

目录
相关文章
|
3月前
|
C++
记录一次循环引用的问题
记录一次循环引用的问题
|
3月前
|
缓存 Java 程序员
Java垃圾回收: 什么是强引用、软引用、弱引用和虚引用?
Java垃圾回收: 什么是强引用、软引用、弱引用和虚引用?
32 2
|
6月前
|
SQL 缓存 移动开发
Java内存泄漏知识(软引用、弱引用等)
要学习内存泄漏,我们要知道一些基础知识,如Java引用分类:
|
9月前
|
Java
强引用、软引用、弱引用、虚引用的区别?
强引用、软引用、弱引用、虚引用的区别?
65 0
|
9月前
|
Java
JVM学习日志(八) 强引用,软引用,弱引用,虚引用
强引用,软引用,弱引用,虚引用 简述
65 0
JVM学习日志(八) 强引用,软引用,弱引用,虚引用
|
9月前
|
算法 Java C++
14-理解Java中的不同引用类型:强引用、软引用、弱引用和虚引用
这篇文章将深入探讨Java中的四种引用类型:强引用、软引用、弱引用和虚引用。我们将逐一解释每种引用类型的特性和用途。
43 0
14-理解Java中的不同引用类型:强引用、软引用、弱引用和虚引用
|
缓存 监控 Java
【JAVA】强引用、软引用、弱引用、幻象引用有什么区别?
在 Java 语言中,除了原始数据类型的变量,其他所有都是所谓的引用类型,指向各种不同的对象,理解引用对于掌握 Java 对象生命周期和 JVM 内部相关机制非常有帮助。
99 0
|
缓存 Java 关系型数据库
强引用、软引用、弱引用、幻象引用有什么区别和使用场景
强引用、软引用、弱引用、幻象引用有什么区别和使用场景
155 1
|
缓存 Java
强引用、软引用、弱引用、虚引用有什么区别?
本文主要介绍强引用、软引用、弱引用、虚引用
152 0
|
缓存 Java
强引用,软引用,弱引用,幻象引用有什么区别?
强引用,软引用,弱引用,幻象引用有什么区别?
116 0
强引用,软引用,弱引用,幻象引用有什么区别?