OpenResty从入门到实战
温铭
OpenResty软件基金会主席,《OpenResty 最佳实践》作者
立即订阅
4332 人已学习
课程目录
已完结 52 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | OpenResty,为你打开高性能开发的大门
免费
入门篇 (14讲)
01 | 初探OpenResty的三大特性
02 | 如何写出你的“hello world”?
03 | 揪出隐藏在背后的那些子项目
04 | 如何管理第三方包?从包管理工具luarocks和opm说起
05 | [视频]opm项目导读
06 | OpenResty 中用到的 NGINX 知识
07 | 带你快速上手 Lua
08 | LuaJIT分支和标准Lua有什么不同?
09 | 为什么 lua-resty-core 性能更高一些?
10 | JIT编译器的死穴:为什么要避免使用 NYI ?
11 | 剖析Lua唯一的数据结构table和metatable特性
12 | 高手秘诀:识别Lua的独有概念和坑
13 | [视频]实战:基于FFI实现的lua-resty-lrucache
14 | 答疑(一):Lua 规则和 NGINX 配置文件产生冲突怎么办?
API篇 (11讲)
15 | OpenResty 和别的开发平台有什么不同?
16 | 秒杀大多数开发问题的两个利器:文档和测试案例
17 | 为什么能成为更好的Web服务器?动态处理请求和响应是关键
18 | worker间的通信法宝:最重要的数据结构之shared dict
19 | OpenResty 的核心和精髓:cosocket
20 | 超越 Web 服务器:特权进程和定时任务
21 | 带你玩转时间、正则表达式等常用API
22 | [视频]从一个安全漏洞说起,探寻API性能和安全的平衡
23 | [视频]导读lua-resty-requests:优秀的lua-resty-*是如何编写的?
24 | 实战:处理四层流量,实现Memcached Server
25 | 答疑(二):特权进程的权限到底是什么?
测试篇 (5讲)
26 | 代码贡献者的拦路虎:test::nginx 简介
27 | test::nginx 包罗万象的测试方法
28 | test::nginx 还可以这样用?
29 | 最容易失准的性能测试?你需要压测工具界的“悍马”wrk
30 | 答疑(三)如何搭建测试的网络结构?
性能优化篇 (16讲)
31 | 性能下降10倍的真凶:阻塞函数
32 | 让人又恨又爱的字符串操作
33 | 性能提升10倍的秘诀:必须用好 table
34 | 特别放送:OpenResty编码指南
35 | [视频]实际项目中的性能优化:ingress-nginx中的几个PR解读
36 | 盘点OpenResty的各种调试手段
37 | systemtap-toolkit和stapxx:如何用数据搞定“疑难杂症”?
38 | [视频]巧用wrk和火焰图,科学定位性能瓶颈
39 | 高性能的关键:shared dict 缓存和 lru 缓存
40 | 缓存与风暴并存,谁说缓存风暴不可避免?
41 | lua-resty-* 封装,让你远离多级缓存之痛
42 | 如何应对突发流量:漏桶和令牌桶的概念
43 | 灵活实现动态限流限速,其实没有那么难
44 | OpenResty 的杀手锏:动态
45 | 不得不提的能力外延:OpenResty常用的第三方库
46 | 答疑(四):共享字典的缓存是必须的吗?
API网关篇 (4讲)
47 | 微服务API网关搭建三步曲(一)
48 | 微服务API网关搭建三步曲(二)
49 | 微服务API网关搭建三步曲(三)
50 | 答疑(五):如何在工作中引入 OpenResty?
结束语 (1讲)
结束语 | 行百里者半九十
OpenResty从入门到实战
登录|注册

12 | 高手秘诀:识别Lua的独有概念和坑

温铭 2019-06-21
你好,我是温铭。
上一节中,我们一起了解了 LuaJIT 中 table 相关的库函数。除了这些常用的函数外,今天我再为你介绍一些 Lua 独有的或不太常用的概念,以及 OpenResty 中常见的 Lua 的坑。

弱表

首先是 弱表(weak table),它是 Lua 中很独特的一个概念,和垃圾回收相关。和其他高级语言一样,Lua 是自动垃圾回收的,你不用关心具体的实现,也不用显式 GC。没有被引用到的空间,会被垃圾收集器自动完成回收。
但简单的引用计数还不太够用,有时候我们需要一种更灵活的机制。举个例子,我们把一个 Lua 的对象 Foo(table 或者函数)插入到 table tb 中,这就会产生对这个对象 Foo 的引用。即使没有其他地方引用 Footb 对它的引用也还一直存在,那么 GC 就没有办法回收 Foo 所占用的内存。这时候,我们就只有两种选择:
一是手工释放 Foo
二是让它常驻内存。
比如下面这段代码:
$ resty -e 'local tb = {}
tb[1] = {red}
tb[2] = function() print("func") end
print(#tb) -- 2
collectgarbage()
print(#tb) -- 2
table.remove(tb, 1)
print(#tb) -- 1
不过,你肯定不希望,内存一直被用不到的对象占用着吧,特别是 LuaJIT 中还有 2G 内存的上限。而手工释放的时机并不好把握,也会增加代码的复杂度。
那么这时候,就轮到弱表来大显身手了。看它的名字,弱表,首先它是一个表,然后这个表里面的所有元素都是弱引用。概念总是抽象的,让我们先来看一段稍加修改后的代码:
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《OpenResty从入门到实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(17)

  • 燕羽阳
    lua指令是32位,其中6位作为操作码,8位作为本地变量和upvalue寻址(即256个)。类似的限制还有函数中只能定义262144个常量(2^18)

    作者回复: 👍 这些设计到 Lua 虚拟机指令,感兴趣的同学推荐看看张秀宏老师写的《自己动手实现Lua:虚拟机、编译器和标准库》

    2019-07-01
    2
  • 回家
    为什么table的下标是数字时,设置弱表属性是key,不会对其进行垃圾回收,而是table和function时会对其进行垃圾回收?
    2019-06-26
    1
  • 回家
    开篇讲解弱表的例子中,如果table中有对Foo的引用,不是说明Foo占用的内存是有用的吗?为什么要释放Foo占用的内存?什么时候会对其进行了引用,反倒希望设置弱表属性,希望GC对其进行垃圾回收呢?
    2019-06-26
    1
  • fjpcode
    既然函数是一等公民,和变量一样,那么在一个函数中调用另一个函数是否也属于闭包的范畴。全局变量是否也属于upvalue。
    2019-08-09
  • 英雄
    local t = cjson.empty_array
    这行代码没看懂

    作者回复: 这是把 cjson 这个模块的 empty_array 函数,赋值给了 t 这个变量。在 Lua 中函数是一等公民,可以像变量一样使用

    2019-07-11
  • Leon📷
    coroutine 0:
      /usr/local/openresty/nginx/lua/hello.lua: in main chunk, client: 127.0.0.1, server: localhost, request: "GET /lua HTTP/1.1", host: "localhost"
    2019/07/09 14:21:09 [error] 854136#854136: *16 lua entry thread aborted: runtime error: /usr/local/openresty/nginx/lua/hello.lua:17: attempt to index global 'cjson' (a nil v
    stack traceback,老师,这个是怎么回事

    作者回复: 能否贴下具体的代码?给个 github 的 gist 地址就行

    2019-07-09
  • 小飞哥 ‍超級會員
    上面有个例子, 发现是有两个结果的, 一个是2, 另一个结果是空, 而例子只列出一个结果, 而 第一个print 才是2, 第二个print 是空。

    localhost: ~/geektime/lua $ resty -e '
    > local function foo()
    > local i = 1
    > local function bar()
    > i = i + 1
    > print(i)
    > end
    > return bar
    > end
    > local fn = foo()
    > print(fn())
    > '
    2
    2019-07-02
  • 回家
    老师,typo:”即使这个变量并不在 foo 里面定义“,应该是”即使这个变量并不在 bar 里面定义“~~

    作者回复: 多谢反馈,已经修改:)

    2019-06-26
  • soooldier
    看完后对week table还是完全懵的,有没有更浅显易懂的文章呢?

    作者回复: 可以看 Lua 作者写的那本书,就是《Lua 程序设计》,里面专门有讲 weak table

    2019-06-24
  • 小飞哥 ‍超級會員
    写在最后的do end 是不是表示代码块的意思?
    do end封装后是不是其它function是无法访问的?

    作者回复: 是的,除非你在 do end 之前预定义了一个变量,比如:
    local f
    do
    function f()
    ...
    end

    end -- do

    2019-06-22
  • 一步
    local cjson = require('cjson')
    local tb1 = {}
    setmetatable(tb1, cjson.empty_array_mt)
    print(cjson.encode(tb1))
    tb1['key'] = '11'
    print(cjson.encode(tb1))

    老师这样写之后打印出来 4个 [] 空数组,最后那个那个不是赋值了吗? 为什么还是空数组呢?
    2019-06-22
  • 罐头瓶子
    upvalue 上线250这个是考虑到变量查找效率的问题?如果local变量过多可以放在table里面加快查找效率?

    作者回复: 其实上限是 256, 这个是 Lua 虚拟机的指令占用的大小决定的。超过 256 的话,Lua 虚拟机就不支持了。

    2019-06-21
  • helloworld
    老师,我这么理解对不对:
    OpenResty的API包括Nginx API和LuaJIT API,Nginx API主要是lua-nginx-module等*-nginx-module C模块提供的API,而LuaJIT API主要是lua-resty-*各种Lua库所提供的API
    2019-06-21
  • helloworld
    老师,文中提到的OpenResty的API和LuaJIT的API,你看我这么理解对不对:
    OpenResty的API,是指lua-nginx-module模块提供的API
    LuaJIT的API,是指lua-resty-core和各种lua-resty-*项目中提供的API

    作者回复: OpenResty 的 API 指的是lua-nginx-module和lua-resty-core提供的接口,都是 `ngx` 来头的;LuaJIT 的 API 是扩展了 Lua 内置的库,比如 `table.new` 这种

    2019-06-21
    1
  • xindoo
    我立即lua中的弱表和java中的WeakHashMap类似
    2019-06-21
  • 一步
    当 __mode = k 时 ,table 的键k是弱引用, 这句话不知道怎么理解, 键也可以计数吗? 键也可以弱引用吗?
    table 的 值 v是弱引用, 可以理解的, 当回收的时候 赋值为 nil
    2019-06-21
  • 一步
    lua weak table 可以类比 js 的 weak set ,其中的元素不会加入引用计数,当元素没有其他引用的时候,就会被 gc 掉
    2019-06-21
收起评论
17
返回
顶部