• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2023-08-11 16:53 Aet 隐藏边栏 |   抢沙发  9 
文章评分 3 次,平均分 5.0

概述

  1. 通过标准库和 C APILua 可以轻松地与 C 和其他编程语言集成

语法简述

数据结构

  1. nil: 用于表示不存在的值。
  2. boolean: 包括 true false
  3. number: 默认情况下,Lua 5.3 之后的版本使用双精度浮点数表示。
  4. string: 用于表示不可变的字符序列。
  5. table: 表是 Lua 的主要数据结构,它们是关联数组,可以用来表示数组、集合、记录等。
  6. function: 在 Lua 中,函数是第一类值,可以存储在变量中,作为参数传递等。
  7. thread: 用于表示协程。
  8. userdata: 用于表示 C 中的任意数据

函数和闭包

  1. Lua 支持高阶函数和词法闭包。
  2. 这允许强大和灵活的编程范式,例如函数式编程

协程

  1. Lua 支持协程,这是一种轻量级线程的概念,可以用于编写复杂的非阻塞逻辑

元表和元方法

  1. Lua 的表可以附加元表,定义一些特殊行为,如运算符重载

垃圾收集

  1. Lua 使用自动内存管理,包括一个增量垃圾收集器来回收不再使用的内存

C API

跨平台

  1. Lua 是跨平台的,可以在许多操作系统和架构上运行

理解相关

解释器单独运行

  1. 下面的进程地址空间是属于lua解释器自己的进程地址空间
  2. 解释器单独运行时,和普通的程序一样,同样的进程地址空间(以下由高地址向低地址):
    1. 内存映射区
      1. 存放动态链接库和共享库,以及用于进程间通信的共享内存等
    2. 栈区
      1. C 调用栈,用于存储 Lua 解释器本身的函数调用信息以及与 C 函数交互时的信息
    3. 堆区
      1. Lua 的对象(例如表、字符串等)
      2. Lua 的虚拟栈都是在堆上分配的
    4. 数据区
      1. bss段存放未初始化的数据(全局变量或静态变量)(地址大一些)
      2. 初始化过的数据段存放初始化的全局变量或静态变量
      3. 全局和静态的 Lua 变量可能位于宿主进程的数据段中,也包括了解释器自身的全局和静态数据
    5. 代码区
      1. 存放程序的可执行代码。
      2. 这部分内存通常是只读的,以防止程序在运行时修改自己的指令
      3. Lua 解释器的代码本身通常存储在宿主进程的文本段中

解释器在宿主程序中运行

  1. 下面的进程地址空间是属于宿主自己的进程地址空间
  2. 宿主进程地址空间(以下由高地址向低地址):
    1. 内存映射区
      1. 存放动态链接库和共享库,以及用于进程间通信的共享内存等
      2. 如果 Lua 作为动态链接库嵌入,则它可能会位于内存映射段中
    2. 栈区
      1. 宿主程序和嵌入的 Lua 解释器共享相同的调用栈
      2. 当从 C 代码调用 Lua 函数或从 Lua 调用 C 函数时,将使用此共享栈
    3. 堆区
      1. Lua 的对象(例如表、字符串等)
      2. Lua 的虚拟栈都是在堆上分配的
      3. 动态分配的其他数据结构,如协程对象,哈希表等
    4. 数据区
      1. bss段存放未初始化的数据(全局变量或静态变量)(地址大一些)
      2. 初始化过的数据段存放初始化的全局变量或静态变量
      3. 全局和静态的 Lua 变量可能位于宿主进程的数据段中,也包括了解释器自身的全局和静态数据
    5. 代码区
      1. 存放程序的可执行代码。
      2. 这部分内存通常是只读的,以防止程序在运行时修改自己的指令。
      3. Lua 解释器的代码本身通常存储在宿主进程的文本段中

虚拟栈

  1. Lua 的虚拟栈为每个活动函数(包括 Lua 函数和 C 函数)维护一个栈帧。
    1. 每个栈帧包含该函数的局部变量、临时值、返回地址等。
  2. 在运行时,Lua 解释器将管理虚拟栈的大小和组织
    1. 包括在调用新函数时创建新的栈帧
    2. 在函数返回时销毁栈帧
    3. 以及必要时扩展或收缩虚拟栈的大小
  3. 由于虚拟栈在堆区分配,所以它可以灵活地进行这些操作,而不受固定大小限制
    1. 虚拟栈使得 Lua 可以方便地实现诸如尾递归优化和协程等特性

lua局部变量

  1. 局部变量存储在虚拟栈的栈帧中,而虚拟栈自身通常位于堆区。

lua全局变量

  1. Lua 中,全局变量实际上是存储在一个特殊的表中的
    1. 这个表被称为全局环境表(通常标识为 _G
  2. 当你在 Lua 中创建一个全局变量时,实际上是在全局环境表中创建了一个键值对

  1. 全局环境表的键和值可以是除 nil 外的任何类型

表的底层实现

  1. Lua 表是一种非常灵活和强大的数据结构,可以视为关联数组或哈希表

  2. Lua 表的底层实现是通过两部分组合来的:

  3. 数组部分:

    1. 键是连续的正整数,不需要额外的信息来表示类型
    2. 这部分存储连续的整数索引的值
    3. 数组部分通常实现为一个连续的内存区域,每个元素包括键和值
    4. 通过键作为索引,可以在常数时间内访问对应的值。
  4. 哈希部分:

    1. 用于非连续整数索引和非整数键
      1. 键可以是任何非 nil 类型
      2. 在查找哈希表中的元素时,键的类型会直接用于计算哈希值和解决冲突
      3. 这种情况下,键的类型信息是通过哈希函数和冲突解决策略的实际实现来处理的,而不是存储为键的明确元数据
    2. 它采用标准的哈希表机制,包括冲突解决技术,以处理可能的键冲突
    3. 哈希部分是一个哈希表,其中每个表项包括一个键和对应的值
    4. 当你尝试通过一个键访问值时,Lua 首先会计算该键的哈希值,然后使用哈希值在哈希表中查找键和对应的值
    5. 如果出现哈希冲突(不同的键具有相同的哈希值),Lua 会使用开放寻址或其他冲突解决技术找到正确的表项

    关于键值

  5. 根据上面的解释,键可以是数字,也可以是其他的数据类型数据

    1. 具体看上一条
  6. 关于值:

    1. 值是一个元素,每个元素可能包括以下内容
    2. 值的实际数据
    3. 类型信息
    4. 其他可能的元数据

关于协程

  1. Lua 的协程是一种非抢占式的多任务处理机制,允许多个独立的控制流共享同一个线程

  2. 协程提供了协作式多任务的功能,其中每个协程只在显式让出(yield)时挂起执行,并允许另一个协程运行

  3. 以下是 Lua 协程的一些主要组成部分和实现细节:

  4. 协程创建

    1. 可以使用 coroutine.create 来创建新的协程
    2. 然后使用 coroutine.resumecoroutine.yield 来控制协程的执行
    3. 每个协程在内部都与一个 Lua 函数相关联,当你恢复协程时,这个函数开始执行
  5. 协程状态

    1. 每个协程都有自己的状态,可以是 "running""suspended""normal""dead"
    2. 状态决定了协程在何时可以恢复或挂起
  6. 协程虚拟栈

    1. 每个协程都有自己的虚拟栈,用于存储局部变量和其他执行状态
    2. 当协程挂起时,它的虚拟栈的内容会被保存,当协程恢复时,虚拟栈的内容会被恢复
    3. 这允许每个协程保持自己的执行上下文。
  7. 挂起与恢复

    1. 通过调用 coroutine.yield,协程可以让出控制,将执行权交还给调用它的协程或主线程
    2. coroutine.resume 可用于恢复先前挂起的协程的执行
    3. 这些函数允许协程之间传递值,实现协程之间的通信。
  8. 非抢占式

    1. Lua 的协程调度是非抢占式的,这意味着协程必须显式让出控制权才能允许其他协程运行
  9. 与线程区别

    1. Lua 协程提供了类似于线程的并发执行功能,但它们与操作系统线程有明显的区别
    2. 协程共享同一个线程和内存空间,并通过协作调度而非抢占调度运行
    3. 这使得协程在许多情况下更轻量和更容易管理,但也意味着它们不利用多核处理器的并行能力

协程栈数据结构

  1. 当协程挂起时,它的虚拟栈的内容被保存在内存中与那个协程关联的数据结构中
  2. 这个结构保持了协程的所有执行上下文,包括:
    1. 调用栈:保存了协程中所有函数调用的历史,以及每个函数调用的局部变量、上值(upvalues)和其他相关状态
    2. 程序计数器:表示了协程在挂起时所在的代码位置
    3. 其他相关状态:包括闭包、元表、错误处理函数等

垃圾回收机制

  1. Lua 使用一个称为垃圾收集(Garbage Collection,GC)的机制来自动管理内存,确保不再使用的对象被正确地回收以释放内存。
  2. Lua 的垃圾收集器是一个增量收集器,并提供一些调优参数以适应不同的使用场景
  3. 可达性分析
    1. Lua 垃圾收集的核心思想是通过可达性分析来确定哪些对象是“活动的”或“死亡的”。
    2. 如果一个对象可以从根通过一系列引用访问到,那么它就被认为是活动的
    3. 否则,它就是死亡的
  4. 标记清楚算法
    1. Lua 使用了一种称为标记-清除(Mark-and-Sweep)的算法。该算法分为两个阶段:
    2. 标记阶段:在这个阶段,垃圾收集器从一组根对象(例如全局变量)开始,遍历所有可从根访问的对象,并将这些对象标记为可达
    3. 清除机制:在这个阶段,垃圾收集器遍历所有对象,并释放那些未被标记为可达的对象的内存
  5. 增量收集
    1. Lua 垃圾收集器的一个重要特性是它的增量性
    2. 这意味着它不是一次执行完整的标记-清除周期,而是将其分为多个较小的步骤
    3. 这有助于减少垃圾收集过程对程序性能的影响
  6. 弱引用表
    1. Lua 还支持弱引用表,这些表允许引用对象但不阻止它们被垃圾收集
    2. 这对于实现缓存和其他需要精细控制内存管理的高级模式非常有用
  7. 手动控制和调优
    1. Lua 提供了一组函数,例如 collectgarbage,允许你与垃圾收集器进行交互,执行诸如手动启动垃圾收集周期或设置收集器参数等操作

C语言中创建的表

  1. 不会存到全局变量环境表里,而是存在于lua栈里面
  2. 除非显示指定:

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0 最后编辑于:2024-06-13
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享