内存分配

简介: 内存分配

Lua 语言核心对内存分配不进行任何假设,它既不会调用 malloc 也不会调用 realloc 来分配内存。相反, Lua 语言核心只会通过一个分配函数( allocation function )来分配和释放内存,当用户创建 Lua 状态时必须提供该函数。


luaL_newstate 是一个用默认分配函数来创建 Lua 状态的辅助函数。该默认分配函数使用了来自 C 语言标准库函数 malloc-realloc-free ,对于大多数应用程序来说,这几个函数(或应该是)够用了。但是,要完全控制 Lua 的内存分配也很容易,使用原始的 lua_newstate 来创建我们自己的 Lua 状态即可:

lua_State *lua_newstate (lua_Alloc f, void *ud);点击复制复制失败已复制


该函数有两个参数:一个是分配函数,另一个是用户数据。用这种方式创建的 Lua 状态会通过调用 f 完成所有的内存分配和释放,甚至结构 lua_State 也是由 f 分配的。

分配函数必须满足 lua_Alloc 的类型声明:

typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);点击复制复制失败已复制


第一个参数始终为 lua_newstate 所提供的用户数据;第二个参数是正要被(重)分配或者释放的块的地址;第三个参数是原始块大小;最后一个参数是请求的块大小。如果 ptr 不是 NULLLua 会保证其之前被分配的大小就是 osize (如果 ptrNULL ,那么这个块之前的大小肯定是,所以 Lua 使用 osize 来存放某些调试信息)。


Lua 语言使用 NULL 表示大小为零的块。当 nsize 为零时,分配函数必须释放 ptr 指向的块并返回 NULL ,对于所要求的大小(为零)的块。当 ptrNULL 时,该函数必须分配并返回一个指定大小的块;如果无法分配指定的块,则必须返回 NULL 。如果 ptrNULL 并且 nsize 为零,则两条规则都适用;最终结果是分配函数什么都不做,返回 NULL


最后,当 ptr 不是 NULL 并且 nsize 不为零时,分配函数应该像 realloc 一样重新分配块并返回新地址(可能与原地址一致,也可能不一致)。同样,当出现错误时分配函数必须返回 NULLLua 假定分配函数在块的新尺寸小于或等于旧尺寸时不会失败( Lua 在垃圾收集期间会压缩某些结构的大小,并且无法从垃圾收集时的错误中恢复)。


lua_newstate 使用的标准分配函数定义如下(从文件 lauxlibe.c 中直接抽取):

static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
  (void)ud; (void)osize;  /* not used */
  if (nsize == 0) {
    free(ptr);
    return NULL;
  }
  else
    return realloc(ptr, nsize);
}点击复制复制失败已复制


该函数假设 free(NULL) 什么也不做,并且 realloc(NULL, size) 等价于 malloc(size)ISO C 标准会托管这两种行为。


我们可以通过调用 lua_getallocf恢复recoverLua 状态的内存分配器:

lua_Alloc lua_getallocf (lua_State *L, void **ud);点击复制复制失败已复制


请记住,所有新的分配函数都有责任释放由前一个分配函数分配的块。通常情况下,新的分配函数是在旧分配函数的基础上做了包装,来追踪分配trace allocation )或同步访问heap )的。


Lua 在内部不会为了重用而缓存空闲内存。它假定分配函数会完成这种缓存工作;而优秀的分配函数确实也会这么做。 Lua 不会试图压缩内存碎片。研究表明,内存碎片更多是由糟糕的分配策略导致的,而非程序的行为造成的;而优秀的分配函数不会造成太多内存碎片。


对于已有的优秀分配函数,想要做到比它更好是很难的,但有时候也不妨一试。例如 Lua 会告诉你已经释放或者重新分配的块的原有大小。因此,一个特定的分配函数不需要保存有关块大小的信息,以此减少每个块的内存开销。


还有一种可以改善的内存分配的场景,是在多线程系统中。这种系统通常需要对内存分配函数进行线程同步,因为这些函数使用的是全局资源(堆)。不过,对 Lua 状态的访问也必须是同步的——或者更好的情况是:限制只有一个线程能够访问 Lua 状态。因此,如果每个 Lua 状态都从私有的内存池中分配内存,那么分配函数就可以避免线程同步导致的额外开销。

目录
相关文章
|
应用服务中间件
【IDEA乱码解决方案】IDEA控制台乱码解决方案收集
【IDEA乱码解决方案】IDEA控制台乱码解决方案收集
341 0
|
10月前
|
安全 Linux 虚拟化
|
数据处理 定位技术 开发者
甘特图、IPO图、DFD图
甘特图、IPO图、DFD图
|
12月前
|
关系型数据库 Serverless 定位技术
PostgreSQL GIS函数判断两条线有交点的函数是什么?
PostgreSQL GIS函数判断两条线有交点的函数是什么?
782 60
|
存储 关系型数据库 MySQL
手把手教教会你使用Wing FTP Server安装配置并结合内网穿透实现公网访问本地站点
手把手教教会你使用Wing FTP Server安装配置并结合内网穿透实现公网访问本地站点
|
数据挖掘 API 开发者
​Email API有哪些,最好的3个API接口有哪些
Email API如SendGrid、Mailgun和AOKSend是企业自动化邮件通信的关键工具。它们提供邮件发送、接收和管理功能,提升效率,优化客户体验。SendGrid以其高可靠性、强大分析和易于集成备受青睐;Mailgun以灵活性和高发送率著称;而AOKSend则以其高效、详细分析和易用性脱颖而出。通过使用这些API,企业能实现定制化邮件服务,跟踪性能,提升邮件营销效果。
|
SQL DataWorks 数据库连接
DataWorks操作报错合集之在 DataWorks 中,尝试访问数据源时遇到“没有权限”的错误,如何解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
293 0
|
前端开发 安全 JavaScript
基于Springboot实现校园疫情防控管理系统平台(一)
基于Springboot实现校园疫情防控管理系统平台
265 0