作者:chrongzhang,腾讯 WXG 客户端开发工程师
这是一篇介绍微信小游戏客户端底层,如果进行优化,可以让所有小游戏获得更好性能的文章 。不是你想像的怎么优化某个小游戏的文章 。来都来了,就了解一下吧:)小游戏主要分为渲染和逻辑两部分 。渲染优化能让渲染相关的指令(WebGL/GFX)得到更高效的执行,逻辑优化是让除渲染之外的代码也能更高效的执行,本篇主要讲述逻辑相关的优化 。
基础功能优化V8微信小游戏是在 2017 年 12 月 28 日上线的,当时微信Android/ target=_blank class=infotextkey>安卓客户端使用的 V8 版本还是 5.5 。而 google 在 V8 上的迭代速度是很快的,其中一个大的版本变更是从 5.9 版本开始,编译器由原来的 FullCodeGenerator + Crankshaft 变更成更加高效的 Ignition + TurboFan 。
文章插图
mark
V8 引擎之所以性能高,在于其出色的 JIT 执行效率 。JIT 依赖了一个可以在运行时优化代码的动态编译器 。V8 早期的 JIT 编译器是 FullCodegen,后来是 Crankshaft,然后是一直沿用至今的 Turbofan 。
升级 V8,可以获得更高的执行性能(TurboFan)、更快的启动速度(Snapshot + Code Caching)、更低的内存占用(64 位压缩指针) 。小游戏上线至今,客户端使用的 V8 也一直在升级当中,从最初的 5.5,升级到 6.6,然后是 7.6,直到目前的 8.0 。
JSBinding微信小游戏对开发者暴露的是 JS 的接口,开发者调用某些 JS 函数时,最终会调用到客户端底层的原生能力 。而从 JS 到客户端底层之间的桥接能力,就是所谓的 JS 绑定 。JS 绑定又分为两种:裸绑定和非裸绑定 。裸绑定是通过 V8/JAVAScriptCore 提供的原生接口,将某个 JS 函数和原生函数实现绑定到一起,这是最直接,也是最高效的绑定方式 。
非裸绑定是指通过某个 JS 和原生的通信的桥梁(evaluate/prompt/postMessage 等等),在此基础上再封装和转发具体的函数调用 。由于存在中间一层的转发处理,会有额外的消耗 。因此小游戏对外提供的 WebGL 等接口的实现,都采用了裸绑定的方式 。直接用原生裸绑定的 API,又会存在以下问题:
- 原生 API 使用较复杂
- 不方便实现更高层次的类绑定
- V8 和 JavaScriptCore 的 API 差异很大,两个平台需要重复实现绑定
具有如下特点:
- 简单易用,支持类绑定
- 裸绑定,性能高
- 同时支持 V8 和 JavaScriptCore
- 支持 node addon 绑定实现
NodeJs/libuv安卓客户端已经全面拥抱 node 。集成 node runtime 后,拥有了如下能力:
- node 内置能力(如文件、setTimeout 等)
- libuv 异步 IO 处理的能力
调用链路优化我们都知道,两点之间,直线最短 。代码也是一样,调用链路越短,越直接,中间的开销就越小 。
JsApi 优化1. JsApi 调用优化首先来看看之前 JsApi 的调用链路:
文章插图
mark
一个 js api 的调用(WeixinJSCore.invokeHandler),首先会调用到 C/C++ 统一的回调函数 voidCallback,然后再通过 JNI 调用到 Java 的统一处理函数 callVoidJavaMethod 。在这个函数里,需要根据 methodID 从 map 中找到对应的 Java Method,然后再通过多次 JNI 调用 J2V8 各种接口将 js api 的参数转换为 Java 类型参数,最后再调用到具体 API 的 Java 实现函数 Invoke 。
这个调用链路显然不是前面提到的裸绑定的实现方法,因为中间还夹了一层 Java 的中转处理层,产生了一些性能消耗 。
针对 invokeHandler,缩短调用链路,减少 JNI 调用优化后,流程如下:
文章插图
推荐阅读
- 微信朋友圈看出人的性格类型
- 女生如何锻炼背部肌肉呢?
- 客厅背景墙颜色风水有讲究
- 家居风水原则不得违背 抵制让人变穷的家居风水
- MySQL索引背后的数据结构及算法原理
- 日本|号称最轻松赚钱方式!日本新奇打工背着电脑走 网友直呼无聊
- 中老年耳背会遗传吗?
- 女性妇科炎症背酸怎么办呢?
- 泰姬陵背后的血腥恐怖袭击 泰姬陵的神秘事件
- 通用搜索引擎背后的技术点