Lua的设计与实现——基础数据类型(字符串)

本文深入探讨Lua字符串的实现,包括内化机制、不可变性、全局字符串区域、散列桶管理及优化。通过字符串的内化,Lua提升了比较和查找操作的性能,减少了内存占用。同时,文章介绍了如何通过散列值快速查找和处理字符串,以及在字符串创建时的优化策略。

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

Lua的设计与实现——基础数据类型(字符串)

出自书籍:李创.Lua设计与实现[M].北京.人民邮电出版社.2017:186.

这次介绍Lua内部字符串的实现原理。首先将概述Lua的实现原理,看看其中设计者主要考虑哪些情况,然后带着这些问题结合具体的代码进行分析。

概述

C语言并不像C++那样,自带处理字符串类型的库,这导致有非常多的C语言库都自己实现了一个处理字符串的类型和相关的API。一般来说,要表示一个字符串,核心就是以下两个数据。

  • 字符串长度。
  • 指向存放字符串内存数据的指针。

当然,Lua自己的字符串类型的实现也没有绕过这两个核心内容。只不过,Lua在这方面显然考虑了更多东西。

在Lua中,字符串实际上是被内化(internalization)的一种数据。怎么理解“内化”的含义呢?简单来说,每个存放Lua字符串的变量,实际上存放的并不是一份字符串数据的副本,而是这份字符串数据的引用。在这个理念下,每当新创建一个字符串时,首先都会去检查当前系统中是否已经有一份相同的字符串数据了。如果存在的话就直接复用,将引用指向这个已经存在的字符串数据,否则就重新创建一份新的字符串数据。

因此,字符串在Lua中是一个不可变的数据,改变一个字符串变量的数据并不会影响原来的字符串的数据。比如,在下面的代码中:

a = "1"
a = a.."2"

第一行代码创建了一个变量a,指向字符串“1”,而在第二行代码中,我们使用…字符串连接符,将变量a后面连接了字符串”2“。第二行代码对变量a的重新修改,并没有影响第一行代码的字符串”1“。换言之,此时系统中存在两个字符串:”1“和”12“。这个变化如图3-1所示。

效果图

图3-1 字符串内化示意图

而前面生成的字符串”1“,如果其他地方没有引用它的话,将在GC阶段被回收。

这里可以看到,为了实现内化,在Lua虚拟机中必然要有一个全局的地方存放当前系统中的所有字符串,以便在新创建字符串时,先到这里来查找是否已经存在同样的字符串。Lua虚拟机使用一个散列桶来管理字符串,这一点来后面再展开讨论。

Lua在字符串实现上使用内化这种方案的优点在于,进行字符串数据的比较和查找操作时,性能会提升不少,因为这两个操作的核心都是字符串的比较。传统的字符串比较算法是根据字符串长度逐位来进行对比,这个时间复杂度与字符串长度线性相关;而内化之后,在已知字符串散列值的情况下,只需要一次整数的比较即可。这个实现还有另外一大好处,那就是空间优化,多份相同的字符串在整个系统中只存在一份副本。Lua是一个在设计之初就把性能、资源占用等放在重要位置的语言,这里再一次得到体现。

当然,这个实现并不是完全没有缺陷的。以前面描述的创建字符串的过程来说,在创建一个新的字符串时,首先会检查系统中是否有相同的数据,只有不存在的情况下才创建,这与直接创建字符串相比,多一次查找过程。好在在Lua的实现中,查找一个字符串的操作消耗并不算大。

整理一下上面的描述,主要有以下几点。

  • 在Lua虚拟机中存在一个全局的数据区,用来存放当前系统中的所有字符串。
  • 同一个字符串数据,在Lua虚拟机中只可能有一份副本,一个字符串一旦创建,将是不可变更的。
  • 变量存放
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值