skynet项目内存使用优化

Skynet/Lua 凭借其轻量易用、灵活热更、Actor并发模型的特性被广泛应用于游戏开发等场景,但 Lua 动态内存管理机制也带来了内存占用过高的挑战。

本文结合我最近对一个 skynet 项目做的内存优化分析经验,做一下分享。

1、lua 内存使用优化

1.1. 减少 lua 函数调用层数

服务端收到协议后,要经过很多次函数调用才到真正的执行函数。以手头的项目举例,服务 A 函数负责接收协议数据,收到数据后,会将协议和参数传给 B 函数处理,B 函数根据定义找到对应的模块和方法,再由 C 函数排队(一个玩家一个队列)调用 D 目录下对应的模块和函数, D 目录的模块再 require 对应的目标模块,才调用到真正的执行函数 E。最后,E 函数还会调用其他模块来完成业务逻辑。

调用层数过深的问题是,lua 要为每个过程保留过程数据,如函数地址、参数等,也就是调用栈信息(CallInfo),也叫栈帧

建议:减少调用层级,可以使用注册回调机制
继续阅读skynet项目内存使用优化

skynet lua生成火焰图

最近在搞skynet生成火焰图, github 上刚好有解决方案 skynet_systemtap_set,但代码比较老旧,不支持新版的 skynet 及 lua5.4

生成火焰图的原理是,利用 systemtap 抓取 lua栈,分析函数代码的热路径。

所以,我在他的基础上,主要处理以下两个问题:
1. lua5.4 内部数据结构做了调整,取代码文件地址、代码行数也有改动。
2. skynet shareproto 结构调整

我修改完的代码也放在github分享,有兴趣的小伙伴可以围观 skynet_systemtap_set
继续阅读skynet lua生成火焰图

游戏服务端架构的思考

我从业游戏服务端有10年了,阶段性做个小结,总结我对游戏服务端的理解,这次就谈下服务端架构以及如何优化。文章就以我的经历作为开头。

写在开头

10年前,我加入了一家pc端的游戏公司,那时候国内端游已经是走向没落的时候了,公司正在开发的游戏是mmorpg,玩法比较像魔兽世界,这款游戏他们在此之前已经开发5年了,导致美术资源在当时看来比较落后了,不像同期火热的页游美术那么精致。

但是我觉得,像魔兽世界这种游戏,玩家大地图的游走和打怪,不同职业的配合和牵制,玩家与玩家之间亲密的合作、激烈的对抗是能补足美术这点不足的,特别是巡游boss,一个肉盾抗几下就挂了,基本需要10-20人通力合作才能把 boss 打死。

很快,大量玩家来玩这个游戏,以及客服收集到的评价验证了我的想法。可令人没想到的是,开发问题很大,这个游戏上线期间每天都有1-2次进程崩溃,玩家数据回档。

很可惜,我不是这个项目的开发,我不了解这个游戏的架构,只是这件事在我的心里埋下了种子,让我萌生想要解决问题的想法。
继续阅读游戏服务端架构的思考

lua table # 取长度问题

任何语言都不是完美无瑕的,在使用中都有各种问题,lua 也不例外。而 lua 使用中,绝对绕不开的一个问题就是 # 取 table 长度问题。

问题描述

先看下 # 的一些使用情况,希望引起你的困惑:

> t = {1,1,nil,1}
> #t
4
> t = {nil,nil,1,nil}
> #t
0
> t = {1,nil,nil,nil,nil,nil,nil,1}
> #t
8
> t[9] = 1
> #t
1
> t = {1,nil,nil,nil,nil,nil,nil,1,1}
> #t
9

当 table 有部分值为 nil 时,你很难清楚 # 取得的结果是什么。(如果你想知道 table 实际长度,只能遍历 table)
继续阅读lua table # 取长度问题

lua定位CPU100%问题

在开始这个话题前,说下我遇到的 skynet 进程 CPU100% 占用问题,查找 bug 的过程比较繁琐,后来想到做改进,这也是促成我写这篇文章的原因。

查到是一段 lua 代码有问题,这里截取其中出问题的代码:

-- 活动开始时间: 2033-01-01 00:00:00
local start_time = 1988121600

function start_activity()
    local now = os.time()
    local diff = now - start_time
    if diff < 0 then
        skynet.timeout((-diff)*100, start_activity)
        return
    end

    -- todo 省略活动内容
end

以上代码,通过 skynet.timeout 设置定时器,定时触发 start_activity , 看似没有问题,但是,当 skynet.timeout 第一个参数过大时,会有意想不到的收获。
继续阅读lua定位CPU100%问题