QQ小游戏显存管理优化

QQ小游戏显存管理优化

今天碰到开发商的小游戏出现因为内存警告的情况而被杀掉的情况,但是调试了该小游戏后发现并没有泄露,小游戏退出时释放了所有内存。

在Xcode里发现内存的使用一直稳定增长,进一个场景会增加10M左右,长时间玩的话内存会爆,应该是没有及时释放导致的,但这个游戏的场景很简单,按理来说不该占用这么多内存。


内存增长曲线

分析问题原因

用Allocation跑了一下,发现内存明显小于Xcode里显示的占用量,并且分配大头在VM这一块,而应用本身在CPU的内存占用并不大。

Allocation

由于Allocation里是看不到VRAM(Video Memory)的使用的,加上VM提供的信息,可以确认内存爆的原因是显存占用过多。

一般来说应用所用的大部分对象都在堆上,应用无法直接操作VM,所以不用过分关心VM的使用情况。但当使用了图形借口的话,系统底层创建一些数据结构保存渲染数据,如IOSurface

调试JS代码发现开发商在JS层对WebGL的对象管理相当随意,基本不考虑复用,而且不会主动删除WebGL对象,而OpenGL会通过对象的句柄做更精细的管理。
这种做法在宿主是浏览器里时问题不大,但在小游戏平台会导致内存回收不及时,随着游戏进程而逐渐累积大量内存。
最后在JS层用JS对象包装了Native创建的texture, buffer等对象,当GC时,被回收的对象会删除对应的Native OpenGL对象。改造原有的删除、缓存逻辑,配合GC回收,小游戏的运行时内存占用小了50M以上。

移动端内存分布

和电脑上显卡自带显存不同,移动端的芯片是一块SOC,整个的VRAM和RAM是在同一块连续的内存区域上,所以访问VRAM与一般的内存访问方式相同。虽然苹果从来没开放自己的芯片设计方案,但是诸多资料显示VRAM和RAM之间其实存在一个“共享内存”,这块内存作为中介可以高速读取,访问带宽是一般RAM的2-8倍,并且GPU和CPU都可以访问。可以推测IOSurface其实就是对这种内存结构封装。

iOS显存

iOS上不能直接操作VRAM,不能像使用RAM一样去寻址,但可以通过OpenGL/Metal、CG等这样的图形接口去间接管理。VRAM拥有更高的带宽,这在数据读写上非常占有优势。比如UIKit的-[UIImage imageNamed:]就会把图像缓存到VRAM里,为后续的显示提供更高的性能。
应用的VM里有很大一部分都和显存相关,如VM:IOSurface, VM:CoreAnimation等等。

IOSurface

IOSurface是MAC和iOS上用来存储FBO、RBO等渲染数据的底层数据结构。IOSurface长久以来只有MAC才可以使用,用它可以实现跨进程的渲染,在iOS上的使用非常受限,只开放了很基础的功能,可以用来在不同渲染框架如CoreGraphics, OpenGL, Metal之间传递纹理数据等。

之前的Allcation截图里有3个IOSurface对象就占用了7.86M,可见这个类是比较占内存的。
IOSurface最强的是提供了CPU里访问VRAM的方式。比如创建IOSurface对象之后,在CPU往对象里塞纹理数据,GPU就可以直接使用纹理,所以之前推测IOSurface就是封装了之前提到的那种中介内存。

IOSurface 这个数据结构是和硬件强相关的,之前盘古越狱就是利用了这个接口来破解,获取了最高权限。

小游戏显存管理优化

小游戏的架构特点是JS层驱动Native实现渲染逻辑。而我们要做的就是保证JS层逻辑运行正确的情况下尽量占用最少的内存, 以下是目前主要使用的方法。

懒加载

当JS层创建一个纹理对象时,底层不会立即创建对应的对象, 而是记录下它对应的纹理单元、绑定信息、纹理数据,当它最终有效使用时才在GPU上分配内存创建。

var texture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);//1 激活
gl.bindTexture(gl.TEXTURE_2D, texture);//2 绑定
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);//3 加载数据
//...
gl.drawArrays(mode, first, count);

当纹理对象在Native层最终没有绑定或者加载纹理数据的话,那这个纹理对象判断为无效的,最终不会创建。

OpenGL对象释放时机优化

当开发商在JS层创建GL对象时,OpenGL函数虽然是返回一个句柄,但会包装句柄成一个JS对象返回给JS,并记录在当前WebGLContext。当这个JS对象被GC时,开发商主动调用delete操作时,或者当前WebGLContext释放时,会删除其对于的OpenGL对象,释放GPU显存。

纹理缓存

在JS传过来的image、imageData、canvas对象做渲染时,Native在上传他们的数据到GPU后,会根据他们的Key来缓存对应的纹理对象,之后的渲染命令会优先从缓存中取纹理,若有就直接使用,不用二次上传到GPU。

纹理共享

利用shareGroup来让不同Context共享纹理,这样在不同Context的纹理对象、图像数据可以直接复用,
不需要先读取到CPU,再塞到对应的纹理中

纹理复用

当JS需要加载或更新一个纹理,如果输入源image、imageData、canvas且满足复用条件时,Native直接拷贝其对应的纹理对象到目标纹理中,不需要CPU作为中介传纹理数据。

纹理LRU离线机制

Native实现了LRU纹理LRU离线缓存机制,若一个纹理长时间没有用到,那么当他被LRU缓存淘汰后会从GPU删除并保存到沙盒里,后续用到才恢复到GPU中。

状态机的管理

Native层实现了一套状态机来记录GL对象的信息、渲染的状态。
当需要在不同Context之间传递GL对象时可以直接利用状态机操作。还可以利用状态机的信息可以减少GL对象的的冗余操作,如一个纹理不会重复加载同一张图像。

面向未来

上面提到的方法主要是优化小游戏运行时的显存占用,在iOS上只能通过Xcode memory report看到RAM+VRAM使用情况。除此之外,还有Program、Shader对象,字体对象可以复用,离屏GLContext复用等等方法没有应用。在未来的工作里,会继续努力降低小游戏的内存占用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容