腾讯2020 unreal虚幻面试题

有朋友去TX面试了一下unreal的客户端开发,解析一下他的问题,腾讯的unreal客户端面试题:

1.lua性能优化的方向

    申请的内存,是造成卡顿的原因之一,在C++与lua交互中,如果参数或者返回值有类变量,那么这个变量不会再交互的栈中存放数据,而会通过申请内存,再指定在交互,这样就造成卡顿,因此可以通过把C++的对象的每个参数分开单独传递,可以解决问题,当时我们游戏改完这个问题后,整体提升了2帧。

    其实,主要是Tick循环中,减少与C++的交互,需要的数据不要每帧都去拿,其次,经常拿的一些数据(比方说主角信息),可以做一个lua缓存,在lua中获取。

2.ui 排行榜做法

    分页请求数据,间隔更新数据,ui窗口池,循环使用

3.ui层级管理,以及显示

    主要是通过树实现,子树ui后渲染,同级按照从上到下的顺序渲染,通过设计

4.ui渲染的底层实现

    我们使用CEGUI渲染,原理可以参考下面博客:

    https://blog.csdn.net/pizi0475/article/details/6323860

5.jenkins 流水线有哪些步骤

  • SVN最新拉取
  • 调用unity相关生成逻辑
  • 打包代码
  • 发布
  • 通知

6.ios打包流程

  • 证书申请 https://developer.apple.com,进入开发者账号中心
  • 申请App IDs

  •  添加测试机 

  •  新建开发证书描述文件

  • 打包时指定对应的钥匙串 

7.武器的生产流程

    2D原画图 -> 3D模型 -> 蒙皮 -> 动作 -> 皮肤生产 

8.帧同步原理

    每个client上报自己的输入,server负责收集每帧所有client的输入,并下发给每个client,client根据输入计算状态,并表现

9.udp的弊端

    包乱序,丢包问题

10.帧同步怎么防作弊

    https://www.zhihu.com/question/58909016  知乎大佬们讨论的基本都有了

11.弱网 怎么处理丢包以及网络抖动

    弱网,需要保持画面流畅,可以通过增加jitterbuffer(根据网络抖动值,计算出的一个值,表示当前客户端可以缓存的最大帧,不会一次执行完,而会还是每个逻辑帧执行一帧,服务器即便发过来多帧,也不会一下执行完)

12.移动同步怎么做的

    预测的话,就是client计算的结果,然后每段时间会跟服务器的结果进行对比,算上RTT相差在一定的范围内,去校验,不对会进行拉扯,或者加速,减速去拟合。

13.ECS的最大优势

  •     因为组件的数据存储在一起,因此对于大量具有相同行为的对象处理,可以大大增加缓存命中率;
  •     可以保存快照信息,做录制与回放

14.几种GC算法

    这个网上有很多详细的教程,但是推荐一下快速了解的:https://www.jianshu.com/p/4c8333f77e39

15.堆排序

    看了不少,觉得这个比较通俗易懂:https://www.cnblogs.com/chengxiao/p/6129630.html

16.反射原理,以及应用

腾讯2020 unreal虚幻面试题_第1张图片

我们生成的dll程序集,会把我们的class method property field event等信息一起保存在一个类似lookup的表中,当我们使用反射的时候,会从里面找。

应用:1.通过反射获取带同样attribute标签的class,然后进行处理

2.通过反射“name”获取assembly中的类的类型,从而创建该类

3.通过方法名,获取类的方法,并调用

17.C++ 多态,多态继承是怎么做的

    编译时多态:重载(运算符,函数)

    运行时多态:通过virtual关键字标记,虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。虚函数通过虚表实现,类或者父类含有virtual标记的函数的时候,该类会生成一个虚指针,以及一个VTable,VTable保存本类所有的虚函数,因此在向上转换后,调用同名函数,还是会调用子类的VTable中的函数。

    多态在继承的情况下,对新类的创建会先创建一个VTalbe,把父类的虚函数加入VTable,对于没有重新定义的虚函数使用基类函数的地址,对于重新定义的,使用子类的函数地址,新增的直接加入VTable。

18.C++11 可变长模板

    https://www.cnblogs.com/tekkaman/p/3501122.html

19.函数什么情况下会发生链接失败

    当编译器遇到一个模板定义时,它并不生成代码。只有当我们实例化出模板的一个特定版本时,编译器才会生成代码。当我们使用(而不是定义)模板时,编译器才生成代码,这一特性影响了我们如何组织代码以及错误何时被检测到。
通常,当我们调用一个函数时,编译器只需要掌握函数的声明。类似的,当我们使用一个类类型的对象时,类定义必须是可用的,但成员函数的定义不必已经出现。因此,我们将类定义和函数声明放在头文件中,而普通函数和类的成员函数的定义放在源文件中。
模板则不同:为了生成一个实例化版本,编译器需要掌握函数模板或类模板成员函数的定义。因此,与非模板代码不同,模板的头文件通常既包括声明也包括定义
来源链接:https://www.zhihu.com/question/404644440/answer/1315656973

20.C++ static_cast、dynamic_cast

  •     static_cast:static_cast< new_type >(expression) 

说明:将expression 的类型转换为new_type ,没有运行时类型检查保证装换的安全性

用法:

        1.类层次中,基类与子类的指针或者引用转换,向上安全

        2.基本数据类型转换,安全性开发人员保证

        3.void*转换为目标类型指针,不安全

        4.把任何类型的表达式转为void*

  •    dynamic_cast:dynamic_cast< new_type >(expression) 

说明:new_type必须是类的指针 类的引用,或者void*,new_type与expression必须同为指针或者引用

用法:用于类层次间的向上或者向下转换,向上安全,向下具有安全监测,失败会抛出异常,相对静态转换更安全

21.C++11 右值  以及跟左值的区别

正常我们的语句都是左值引用,在C++11中,标准库在中提供了一个有用的函数std::move,std::move并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast(lvalue);

区别在于右值引用传递后,左值没有引用了,只有右值有了。有点在于传递引用过程中可以减少一次资源的创建和释放。

22.为什么离职

仁者见仁,智者见智了

23.还有什么问题

可以问一些职业规划跟发展的问题,还有一些自己的短板

你可能感兴趣的:(腾讯2020 unreal虚幻面试题)