【lua】tolua(Luajit) require 重复加载了的问题(路径混用斜杠/和点.造成的问题)

news/2024/4/13 11:55:00/文章来源:https://blog.csdn.net/zhenmu/article/details/136451603

最近在分析untiy客户端lua的性能时发现,  真机上有的lua重复加载了2次策划数值表。


打印了一下当时package.loaded (按理require了之后这里会存一下,后面require就不会重复加载了),
发现了存在  data/xxxx  data.xxxx 两个路径的。 


那是项目里 require "data/xxxx"  require "data.xxxx"  两种方式混用造成的。
在Unity编辑器里跑没问题,package.loaded里打印出来都是点.连接的。  但真机上却重复了。

再仔细分析源码问题,发现真机为了编译lua用了luajit (lib_package.c 有个版本 require实现没有 /替换成 .), unity上用的是tolua编出来的dll(macnojit 的 loadlib.c 里 require实现做了/换成.)

简单解决方案,在第一个加载.lua文件开头把require函数重写一下:

-- 保存原始的 require 函数  
local original_require = require  
-- 新的 require 函数,重写路径处理  
function require(modname)  -- 将路径中的斜杠替换为点  local modified_modname = modname:gsub("/", ".")-- 调用原始的 require 函数加载模块  return original_require(modified_modname)  
end  

就能避免这个重复加载了的问题。

真机上跑了一下,运行内存竟然少了近几十M(项目里数值表占用太多吧= =), 加载卡顿也少了一些。


放一下lua源码里的 require实现:
https://www.lua.org/source/5.4/loadlib.c.html


static int ll_require (lua_State *L) {const char *name = luaL_checkstring(L, 1);lua_settop(L, 1);  /* LOADED table will be at index 2 */lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);lua_getfield(L, 2, name);  /* LOADED[name] */if (lua_toboolean(L, -1))  /* is it there? */return 1;  /* package is already loaded *//* else must load package */lua_pop(L, 1);  /* remove 'getfield' result */findloader(L, name);lua_rotate(L, -2, 1);  /* function <-> loader data */lua_pushvalue(L, 1);  /* name is 1st argument to module loader */lua_pushvalue(L, -3);  /* loader data is 2nd argument *//* stack: ...; loader data; loader function; mod. name; loader data */lua_call(L, 2, 1);  /* run loader to load module *//* stack: ...; loader data; result from loader */if (!lua_isnil(L, -1))  /* non-nil return? */lua_setfield(L, 2, name);  /* LOADED[name] = returned value */elselua_pop(L, 1);  /* pop nil */if (lua_getfield(L, 2, name) == LUA_TNIL) {   /* module set no value? */lua_pushboolean(L, 1);  /* use true as result */lua_copy(L, -1, -2);  /* replace loader result */lua_setfield(L, 2, name);  /* LOADED[name] = true */}lua_rotate(L, -2, 1);  /* loader data <-> module result  */return 2;  /* return module result and loader data */
}

用lua翻译就是:

--require 函数的实现
function require(name)if not package.loaded[name] thenlocal loader = findloader(name)	//这一步演示在代码中以抽象函数findloader来表示if loader == nil thenerror("unable to load module" .. name)endpackage.loaded[name] = truelocal res = loader(name)if res ~= nil thenpackage.loaded[name] = resendendreturn package.loaded[name]
end


from Lua-require_lua require原理-CSDN博客


ToLua\macnojit\lua\loadlib.c里的实现     luaL_gsub(L, name, "/", ".");做了替换


static int ll_require (lua_State *L) {const char *name = luaL_checkstring(L, 1);int i;lua_settop(L, 1);  /* _LOADED table will be at index 2 */const char* key = luaL_gsub(L, name, "/", ".");lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");lua_getfield(L, 3, key);if (lua_toboolean(L, -1)) {  /* is it there? */if (lua_touserdata(L, -1) == sentinel)  /* check loops */luaL_error(L, "loop or previous error loading module " LUA_QS, name);return 1;  /* package is already loaded */}/* else must load it; iterate over available loaders */lua_getfield(L, LUA_ENVIRONINDEX, "loaders");if (!lua_istable(L, -1))luaL_error(L, LUA_QL("package.loaders") " must be a table");lua_pushliteral(L, "");  /* error message accumulator */for (i=1; ; i++) {lua_rawgeti(L, -2, i);  /* get a loader */if (lua_isnil(L, -1))luaL_error(L, "module " LUA_QS " not found:%s",name, lua_tostring(L, -2));lua_pushstring(L, name);lua_call(L, 1, 1);  /* call it */if (lua_isfunction(L, -1))  /* did it find module? */break;  /* module loaded successfully */else if (lua_isstring(L, -1))  /* loader returned error message? */lua_concat(L, 2);  /* accumulate it */elselua_pop(L, 1);}lua_pushlightuserdata(L, sentinel);lua_setfield(L, 3, key);  /* _LOADED[name] = sentinel */lua_pushstring(L, name);  /* pass name as argument to module */lua_call(L, 1, 1);  /* run loaded module */if (!lua_isnil(L, -1))  /* non-nil return? */lua_setfield(L, 3, key);  /* _LOADED[name] = returned value */lua_getfield(L, 3, key);if (lua_touserdata(L, -1) == sentinel) {   /* module did not set a value? */lua_pushboolean(L, 1);  /* use true as result */lua_pushvalue(L, -1);  /* extra copy to be returned */lua_setfield(L, 3, key);  /* _LOADED[name] = true */}return 1;
}


https://github.com/LuaJIT/LuaJIT/blob/v2.1/src/lib_package.c  里没有实现替换,这边项目里本来改过的,后来升级一次不小心又改掉这个修改了:

#define KEY_SENTINEL	(U64x(80000000,00000000)|'s')static int lj_cf_package_require(lua_State *L)
{const char *name = luaL_checkstring(L, 1);int i;lua_settop(L, 1);  /* _LOADED table will be at index 2 */lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");lua_getfield(L, 2, name);if (lua_toboolean(L, -1)) {  /* is it there? */if ((L->top-1)->u64 == KEY_SENTINEL)  /* check loops */luaL_error(L, "loop or previous error loading module " LUA_QS, name);return 1;  /* package is already loaded */}/* else must load it; iterate over available loaders */lua_getfield(L, LUA_ENVIRONINDEX, "loaders");if (!lua_istable(L, -1))luaL_error(L, LUA_QL("package.loaders") " must be a table");lua_pushliteral(L, "");  /* error message accumulator */for (i = 1; ; i++) {lua_rawgeti(L, -2, i);  /* get a loader */if (lua_isnil(L, -1))luaL_error(L, "module " LUA_QS " not found:%s",name, lua_tostring(L, -2));lua_pushstring(L, name);lua_call(L, 1, 1);  /* call it */if (lua_isfunction(L, -1))  /* did it find module? */break;  /* module loaded successfully */else if (lua_isstring(L, -1))  /* loader returned error message? */lua_concat(L, 2);  /* accumulate it */elselua_pop(L, 1);}(L->top++)->u64 = KEY_SENTINEL;lua_setfield(L, 2, name);  /* _LOADED[name] = sentinel */lua_pushstring(L, name);  /* pass name as argument to module */lua_call(L, 1, 1);  /* run loaded module */if (!lua_isnil(L, -1))  /* non-nil return? */lua_setfield(L, 2, name);  /* _LOADED[name] = returned value */lua_getfield(L, 2, name);if ((L->top-1)->u64 == KEY_SENTINEL) {   /* module did not set a value? */lua_pushboolean(L, 1);  /* use true as result */lua_pushvalue(L, -1);  /* extra copy to be returned */lua_setfield(L, 2, name);  /* _LOADED[name] = true */}lj_lib_checkfpu(L);return 1;
}


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_998615.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Node.Js编码注意事项

Node.js 中不能使用 BOM 和 DOM 的 API&#xff0c;可以使用 console 和定时器 APINode.js 中的顶级对象为 global&#xff0c;也可以用 globalThis 访问顶级对象 浏览器端js的组成 Node.js中的JavaScript组成 相比较之下发现只有console与定时器是两个API所共有的&#xff…

Linux运维:实现光盘开机自动挂载、配置本地yum源教程

Linux运维&#xff1a;实现光盘开机自动挂载、配置本地yum源教程 一、光盘开机自动挂载1、检查光驱设备2、创建挂载点3、编辑/etc/fstab文件4、测试挂载 二、配置本地yum源(挂载光盘或ISO文件)1、挂载ISO文件2、创建YUM仓库配置文件3、清理YUM缓存并测试 &#x1f496;The Begi…

【QT】创建第一个QT程序

下面的前7个可以先不看&#xff0c;直接从8开始看 1. 创建Qt程序 一个Qt程序的组成部分&#xff1a;应用程序类&#xff0c;窗口类应用程序类个数&#xff1a;有且只有一个QApplication a;如何查看类对应的模块&#xff1a;光标移动到类上&#xff0c;F1qmake模块的名字 2. …

2024 批量下载公众号文章内容/阅读数/在看数/点赞数/留言数/粉丝数导出pdf文章备份(带留言):公众号记忆承载近1500篇历史文章在线查看,找文章方便了

关于公众号文章批量下载&#xff0c;我之前写过很多文章&#xff1a; 视频更新版&#xff1a;批量下载公众号文章内容/话题/图片/封面/音频/视频&#xff0c;导出html&#xff0c;pdf&#xff0c;excel包含阅读数/点赞数/留言数 2021陶博士2006/caoz的梦呓/刘备我祖/六神读金…

分享2024年在家轻松兼职赚钱的5个副业

今天在网上看到这么一句话&#xff0c;真的让我深有感触&#xff1a;“职场人一定要有居安思危的意识&#xff0c;创业的人一定要三思而后行”。在这个瞬息万变的时代&#xff0c;连被视为铁饭碗的公务员、教师等体制内工作都不能保证一辈子的稳定。发展副业&#xff0c;似乎成…

【k8s管理--两种方式安装prometheus】

1、k8s的监控方案 1.1 Heapster Heapster是容器集群监控和性能分忻工具&#xff0c;天然的支持Kubernetes和CoreOS。 Kubernetes有个出名的监控agent–cAdvisor。在每个kubernetes Node上都会运行cAdvisor&#xff0c;它会收集本机以及容器的监控数(cpu,memory,filesystem,ne…

谈谈鸿蒙的跨端技术方案

这两年要说技术上最火的关键字&#xff0c;我想肯定离不开“鸿蒙”两个字。 不管是技术社区还是身边的开发者多多少少都在关注鸿蒙的发展趋势&#xff0c;特别是HarmonyOS NEXT版本将进入独立生态体系&#xff0c;不再兼容安卓应用&#xff0c;在开发者和各个企业间激起了不小…

Reqable爬虫抓包工具(国产网络调试工具)

官网界面截图&#xff1a; 官网地址&#xff1a;https://reqable.com/zh-CN/windows/ 历史由来&#xff1a; Reqable的前身是HttpCanary&#xff08;一款Android平台应用程序&#xff09;&#xff0c;但是国内开发者推翻了所有的技术栈&#xff0c;并用C和Flutter重写&#x…

指纹芯片系列——ACM32FP0 二合一(主控+TK)锁控芯片,ACM32FP4三合一(主控+算法+语音)等介绍

随着智能设备的持续发展&#xff0c;指纹识别技术成为了现在智能终端市场和移动支付市场中占有率最高的生物识别技术。凭借高识别率、短耗时等优势&#xff0c;被广泛地运用在智能门锁、智能手机、智能家居等设备上。 我们推荐的在2015年进入指纹识别应用领域&#xff0c;自研高…

数据结构——lesson7二叉树 堆的介绍与实现

前言&#x1f49e;&#x1f49e; 啦啦啦~这里是土土数据结构学习笔记&#x1f973;&#x1f973; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1f4a5; 所属专栏&#xff1a;数据结构学习笔记 &#x1f4a5;对于数据结构顺序表链表有疑问的都可以在上面数据结…

开发Chrome扩展插件

1.首先开发谷歌chrome扩展插件&#xff0c;没有严格的项目结构目录&#xff0c;但是需要保证里面有一个mainfest.json文件 (必不可少的文件)。在这个文件里有三个属性必不可少&#xff1a;name、version、mainfest_version&#xff1b; // 清单文件的版本&#xff0c;这个必须写…

文献学习-13-机器人顶刊IJRR近期国人新作(2024.3)

一、IJRR简介 The International Journal of Robotics Research&#xff08;IJRR&#xff09;是机器人领域的高水平学术期刊&#xff0c;专注于发布关于机器人技术和相关领域的最新研究成果。IJRR创刊于1982年&#xff0c;是该领域的第一本学术刊物&#xff0c;2022-2023最新影…

c++ 常用的STL

前言 写这篇博客目的是为了记录在刷算法题中使用过的STL&#xff0c;因为有些不太常用的会遗忘。这篇博客只是作为笔记&#xff0c;不是详细的STL&#xff0c;因此只会对常用方法说明&#xff0c;不会详细介绍。此外在后面用到新的STL内容时会再补充。 列队 基础列队 基本列…

SAP PP学习笔记06 - BOM操作(BOM 展开,BOM 使用先一览,BOM比较,批量更改BOM)

上几章学些了BOM的基础知识及Customize的知识&#xff0c;本章来做一些操作。 SAP PP学习笔记04 - BOM1 - BOM创建&#xff0c;用途&#xff0c;形式&#xff0c;默认值&#xff0c;群组BOM等_sap销售bom与生产bom-CSDN博客 SAP PP学习笔记04 - BOM2 -通过Serial来做简单的BOM…

【JavaEE初阶】 JVM类加载简介

文章目录 &#x1f343;前言&#x1f332;类加载过程&#x1f6a9;加载&#x1f6a9;验证&#x1f6a9;准备&#x1f6a9;解析&#x1f6a9;初始化 &#x1f384;双亲委派模型&#x1f6a9;什么是双亲委派模型&#xff1f;&#x1f6a9;双亲委派模型的优点 ⭕总结 &#x1f343…

C语言从入门到精通 第十一章(文件操作)

写在前面&#xff1a; 本系列专栏主要介绍C语言的相关知识&#xff0c;思路以下面的参考链接教程为主&#xff0c;大部分笔记也出自该教程。除了参考下面的链接教程以外&#xff0c;笔者还参考了其它的一些C语言教材&#xff0c;笔者认为重要的部分大多都会用粗体标注&#xf…

IP传输方式——组播

组播作为IP传输三种方式之一&#xff0c;指的是报文从一个源发出&#xff0c;被转发到一组特定的接收者&#xff0c;相同的报文在每条链路上最多有一份。相较于传统的单播和广播&#xff0c;组播可以有效地节约网络带宽、降低网络负载&#xff0c;所以被广泛应用于IPTV、实时数…

虾皮、lazada店铺运营攻略,如何搭建高效、稳定的自养号测评系统

随着电子商务的蓬勃发展&#xff0c;越来越多的人选择在虾皮这样的电商平台上开设店铺&#xff0c;以实现创业梦想。但如何在众多店铺中脱颖而出&#xff0c;成为消费者的首选?本文将为您详细解答“怎么样做好虾皮店铺”&#xff0c;并提供一些实用的运营建议。 一、怎么样做…

C语言从入门到精通 第十二章(程序的编译及链接)

写在前面&#xff1a; 本系列专栏主要介绍C语言的相关知识&#xff0c;思路以下面的参考链接教程为主&#xff0c;大部分笔记也出自该教程。除了参考下面的链接教程以外&#xff0c;笔者还参考了其它的一些C语言教材&#xff0c;笔者认为重要的部分大多都会用粗体标注&#xf…

protobufjs使用教程,支持proto文件打包成typescript或javascript脚本

官方链接&#xff1a;https://docs.cocos.com/creator/manual/zh/scripting/modules/example.html 第一步&#xff0c;安装nodejs。&#xff08;自行安装&#xff09; 安装教程可参考 https://www.runoob.com/nodejs/nodejs-install-setup.html 第二步&#xff0c;创建cocos…