luac、luajit对比
一、前言
luac和luajit都是lua语言的运行时编译器,他们是将lua源码文件,生成为二进制0、1编码的“字节码”程序,这样做的好处是安全且速度快。原来读lua文件要经过一遍语义分析等,现在省掉了中间几个步骤。
安装方法,可以用源码安装,也可以用软件包管理工具安装,以Ubuntu为例:
sudo apt install lua5.1 luajit
安装好后,可以用命令调用查看版本:
现在编写一个循环运算的代码test.lua ,如下所示:
print("test start ...")
local start_t = os.clock()
local a = 0
for i=1,100000000 do
a = a * i / 9
a = a % 32 * 3.1415926
end
local end_t = os.clock()
print("test done -->", tostring(end_t - start_t))
使用命令将源码编译为luac、luajit字节码程序,均以去除调试信息的情况为例,关于包含调试信息的情况,大家可以自己尝试:
luac -o -s test.luac test.lua
luajit -b test.lua test.luajit
二、性能对比
使用lua运行luac字节码程序,使用luajit运行luajit字节码程序,运行速度如下,luajit的性能远远领先于luac。
三、文件格式对比
1、luac
使用hexdump查看test.luac十六进制格式,文件以\x1bLua开头。
使用010Editor,安装luac模板,即可查看结构:
2、luajit
使用hexdump查看test.luajit十六进制格式,文件以\x1bLJ开头,luajit格式文件比luac格式文件更小。
使用010Editor,安装luajit模板,即可查看结构:
四、反编译对比
1、luac
$ luac -l test.luac
main <?:0,0> (26 instructions, 104 bytes at 0x5558a3ea4860)
0+ params, 7 slots, 0 upvalues, 0 locals, 12 constants, 0 functions
1 [-] GETGLOBAL 0 -1 ; print
2 [-] LOADK 1 -2 ; "test start ..."
3 [-] CALL 0 2 1
4 [-] GETGLOBAL 0 -3 ; os
5 [-] GETTABLE 0 0 -4 ; "clock"
6 [-] CALL 0 1 2
7 [-] LOADK 1 -5 ; 0
8 [-] LOADK 2 -6 ; 1
9 [-] LOADK 3 -7 ; 100000000
10 [-] LOADK 4 -6 ; 1
11 [-] FORPREP 2 4 ; to 16
12 [-] MUL 6 1 5
13 [-] DIV 1 6 -8 ; - 9
14 [-] MOD 6 1 -9
15 [-] MUL 1 6 -10 ; - 3.1415926
16 [-] FORLOOP 2 -5 ; to 12
17 [-] GETGLOBAL 2 -3 ; os
18 [-] GETTABLE 2 2 -4 ; "clock"
19 [-] CALL 2 1 2
20 [-] GETGLOBAL 3 -1 ; print
21 [-] LOADK 4 -11 ; "test done -->"
22 [-] GETGLOBAL 5 -12 ; tostring
23 [-] SUB 6 2 0
24 [-] CALL 5 2 0
25 [-] CALL 3 0 1
26 [-] RETURN 0 1
使用luadec反编译为伪代码方法如下,注意选择lua的版本:
git clone https://github.com/viruscamp/luadec
cd luadec
git submodule update --init lua-5.1
cd lua-5.1
make linux
cd ../luadec
make LUAVER=5.1
执行效果如下,除了变量名与源码不一致,其他几乎一样:
2、luajit
与luac反编译后的字节码,十分相似。
$ luajit -bl test.luajit
-- BYTECODE -- test.luajit:0-0
0001 GGET 0 0 ; "print"
0002 KSTR 1 1 ; "test start ..."
0003 CALL 0 1 2
0004 GGET 0 2 ; "os"
0005 TGETS 0 0 3 ; "clock"
0006 CALL 0 2 1
0007 KSHORT 1 0
0008 KSHORT 2 1
0009 KNUM 3 0 ; 100000000
0010 KSHORT 4 1
0011 FORI 2 => 0017
0012 => MULVV 6 1 5
0013 DIVVN 1 6 1 ; 9
0014 MODVN 6 1 2 ; 32
0015 MULVN 1 6 3 ; 3.1415926
0016 FORL 2 => 0012
0017 => GGET 2 2 ; "os"
0018 TGETS 2 2 3 ; "clock"
0019 CALL 2 2 1
0020 GGET 3 0 ; "print"
0021 KSTR 4 4 ; "test done -->"
0022 GGET 5 5 ; "tostring"
0023 SUBVV 6 2 0
0024 CALL 5 0 2
0025 CALLM 3 1 1
0026 RET0 0 1
使用python的ljd库,编写反编译为伪代码脚本:
from ljd.tools import set_luajit_version, process_file
import sys,os
# version is 21, for LuaJIT-2.0.1, version to 20 for LuaJIT-2.0.0
set_luajit_version(21)
process_file(sys.argv[1],sys.argv[2])
执行后效果, 可以看出实际运算过程经过优化,两行运算变为一行运算,效率提高不少:
五、结论
通过多个对比,可以知道luajit优于普通luac的执行效率,并且字节码文件也会更小,方便、轻量,易用!
六、参考链接
https://www.codenong.com/cs106521651/
https://blog.csdn.net/feibabeibei_beibei/article/details/90300720