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

https://blog.51cto.com/u_15293891/2999181

https://github.com/feicong/lua_re

留下评论

您的电子邮箱地址不会被公开。 必填项已用*标注