Lua数据结构和内存占用分析

  由于lua是一个跨平台的脚本语言,会根据平台位数(16bit\32bit)、平台类型(Linux\Windows)、语言标准(C89\C99)、以及编译参数等开启预编译选项,导致基本数据结构的字长和类型会动态变化,以linux_ x86_64 进行编译为基础进行分析介绍,lua版本5.3.4。并根据我们开发过程中一些常见的情景进行分析:

1、基础数据结构

  Lua的基本数据表示方式是type + union的方式,根据不同类型映射到union的不同结构上面统一的表示结构lua_TValue

   typedef union Value {
     GCObject *gc;    /* collectable objects */
     void *p;        /* light userdata */
     int b;          /* booleans */
     lua_CFunction f; /* light C functions */
     lua_Integer i;  /* integer numbers */
     lua_Number n;    /* float numbers */
   } Value;
   
   struct lua_TValue {
     Value value_;
      int tt_;
   } TValue;

  但由于lua_Integerlua_Number在当前平台预处理后,分别定义成long long 和 double类型,所以为方便理解,上述结构经过转义:

   typedef union Value {
     GCObject *gc;    /* collectable objects */
     void *p;        /* light userdata */
     int b;          /* booleans */
     lua_CFunction f; /* light C functions */
     long long i;    /* integer numbers */
     double n;      /* float numbers */
   } Value;
   
   struct lua_TValue {
     Value value_;
      int tt_;
   } TValue;

  在lua5.1版本中,统一使用lua_Number来表示整数和浮点数,而double能够表示的整数大小有限,大概2^52的长度,所以用lua_Number表示一些类型为int64_t的全局唯一id长度不够,类似物品id、角色id。在lua5.3中,上述问题不再存在。

  lua简单数据类型bool、整型、浮点型都是统一用lua_TValue来表示,消耗内存为sizeof(lua_TValue) = 16字节。因此相对C\C++表示整型的char\short\int\int64_t来说,这种数据结构的表示法虽然比较统一,但比较消耗内存。还有一些复杂的数据结构,统一封装在GCObject中。由于5.15.3表示法略有差异,5.1方便理解,如下:

   union GCObject {
     GCheader gch;
     union TString ts;
     union Udata u;
     union Closure cl;
     struct Table h;
     struct Proto p;
     struct UpVal uv;
     struct lua_State th;  /* thread */
   };

2、数据结构的内存占用

  在开发过程中,最常用的数据结构是stingtable类型,那么现在主要分析这两种数据结构的内存占用。

2.1 string 类型

  String又细分为短字符串LUA_TSHRSTR和长字符串LUA_TLNGSTR两种,默认长度小于40的为LUA_TSHRSTR,使用全局stringtable进行管理。即所有短字符串都在stringtable中存放,相同字符串只会有一份实际数据拷贝,每份相同的TString对象只是存放一个hash值,用来索引stringtable。而长字符串则跟普通的GCObject没有差别,相同字符串在内存都是单独一份数据拷贝。在Lua5.1中,没有区分长短字符串,所有的字符串统一在stringtable中存在唯一拷贝。猜想这种改变一是因为长字符串出现相同的情况比较少,二是lua5.1的方式长字符串TString计算Hash是抽取部分字符进行运算,这样的计算方式可能被伪造导致不同字符串的hash值一样,但要是所有字符全用来计算hash又比较耗时。

  下面是一个string类型的GCObject的内存表示,根据长短字符串表示方式不一样:

Lua数据结构和内存占用分析

 

 

2.1.1 内存占用分析实践

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/40d90a672028c9263a52f6444ac70320.html