「7年了!GTA5联机加载还是这么慢??⼀个if语句循环了19.8亿次??你的
CPU在抽烟」
你以为我上GitHub就是在学习?你以为我上GTA5就⼀定是在玩游戏
△Please wait forever to play
在给他爱5中,玩家进⼊线上模式通常需要七⼋分钟,甚⾄⼗⼏分钟,这取决于你的电脑配置,然⽽在单机模式却只需要⼀分钟左右,这让⼈怀疑,这两个模式不是⼀个游戏。
Reddit相关板块发起的调查中,超过80%的玩家,都要等3分钟以上,有的甚⾄超过15分钟。
⽽且,从7年前Online上线到今天,这个情况丝毫没有改善。
暴躁的,已经骂起了脏话……
终于⼀个⼤神玩家T0ST实在忍不了,⽤逆编译器逐条查看运⾏情况,终于到原因。
原来,R星(游戏开发商RockStar)写的代码太低效,加载时,⼀个if语句竟然循环了19.8亿次….
幕后⿊⼿:谁占⽤⼤量时间?
加载GTA 5 Online到底有多慢?
但奇怪的是,如果你选择是故事模式(单机版),加载就会快很多,感觉甚⾄像两个不同的⼯作室开发的游戏。
根据他的的说法,《GTAOL》在启动时游戏存在单线程CPU的瓶颈问题,这会影响⼤多数中低端CPU。当然光是这点⽆法解释⾼端配置运⾏游戏也存在加载速度慢的问题,于是他通过专业代码拆解⼯具发现《GTAOL》程序在运⾏时会“纠结”在⼀个⼤⼩10MB的JSON⽂件⽂件⾝上,虽然不知道这⽂件的作⽤,但是它会让你的CPU反复执⾏上亿次if命令,这效率之低可想⽽知。
于是⼤神T0ST编写了⼀个.dll,将其导⼊进《GTA5》游戏中,并成功让《GTAOL》加载到线上的时间缩短了70%
⼤哥⾸先⽤了最简单的Windows任务管理器,来判断联机版GTA 5在启动时,都调⽤了哪些计算机资源。
在1分钟的时间分界线上,之前是加载的是单机和联机版通⽤的基础内容,之后是联机版独有的内容。
可以看到,联机版GTA 5,加载时调⽤⼤量CPU资源⾄少长达4分钟之久。
⽽同时,内存、GPU、硬盘的使⽤情况⼏乎没有明显变化。
所以,问题⼤概率出在代码上。
“R星代码写太烂!”
⿊客⼤哥在开扒R星代码之前,就说:我闻到⼀股烂代码的味道……
为了出到底那⼀部分程序卡住了CPU,他使⽤了⼯具Luke Stackwalker,对CPU任务堆栈进⾏采样分析。
Luke Stackwalker对于闭源应⽤程序,可以转存正在运⾏的进程堆栈,和当前指令指针的位置,以⼀定时间间隔建⽴⼀个调⽤树。
最后将数据整合,就可以得到程序运⾏统计数据。
从结果上看,⼀共有两个函数“卡住”了CPU:
于是他使⽤专业的代码拆解⼯具,给GTA 5来了⼀个“开膛破肚”。
沿着调⽤栈往下⾛,发现问题出在⼀个sscanf函数上。
sscanf的功能是读取格式化的字符串中的数据,⽽在GTA 5中,它正在读取的是⼀个10M左右,有63000多个条⽬的JSON⽂件。
这个⽂件到底是⼲什么⽤的?⿊客⼤哥推测,这可能是游戏内购商店的相关内容。
在具体运⾏时,sscanf对于每个有效值,逐个读取每⼀个字符,然后返回结果,之后指针移向下⼀个值,循环往复……直到把10M⽂件全部扫⼀遍。
再看第⼆个问题,这是⼀个存储命令,对象是item,具体是什么不得⽽知。
但是保存前,有⼀个if语句,逐⼀⽐较item内项⽬的哈希值,检查它们是否出现在某⼀列表中。
按照他的计算,这⼀步if,要执⾏(63000^2+63000)/2 = 1984531500次!
没错,等待加载前的⼗多分钟⾥,GTA 5⽤你的CPU,执⾏了19.8亿次if命令。
如此简单粗暴的编程思路,让这位⽼哥哭笑不得:任务管理器在哪
既然对象有唯⼀哈希值,那为什么不⽤hash map
现在,GTA 5联机版加载,从原来的6分钟,下降到现在的1分50秒!⽽且这位⼤哥,⽤的还是七⼋年前的硬件配置。
⽬前这位⼤哥已经把⽂件打包放在的GitHub上,只需要去下载就可以