进程,线程,协程区别?
- 进程是系统资源分配的最小单位,线程是cpu调度的最小单位。(每个cpu核心只可以操控一个内核线程。内核线程和用户线程是一对多,一对一,多对多的关系)
- 进程由程序段,数据段和pcb组成,占有内存,而线程除了几乎没有系统资源(每个进程有自己的线程控制块和线程栈)
- 同一个进程可以包含多个线程
- 通信方式:进程,共享内存,管道通信,消息传递。线程共享所处进程的内存地址,直接进行通信(通过全局和静态变量等)。
- 线程切换代价小,进程代价大。
- 协程只是一段程序员自己定义的一段代码逻辑,运行在主线程中,切换几乎没有性能消耗。
栈和堆的区别
- 栈存储值类型,堆存储引用类型。
- 栈内存大小是确定的(windows大约为2m),所以递归过多可能导致栈溢出;数据由高地址向低地址存储;存储方式为连续存储
- 堆的大小不确定,和虚拟内存相关(也就是cpu的寻址能力,例如32位机器做多访问2的32次方字节的数据,等于4gb),存储方式是非连续存储,空闲区间通过链表链接(可适当扩充一下动态分配内存算法,例如首次适应法,最佳最坏适应法等等)。
虚拟内存
- 虚拟内存大小由cpu寻址能力决定,和内存大小无关。
- 由于内存空间有限,所以可以把当前进程用到的页面放入内存,其他页面等需要的时候再从外村调入内存,若内存空间不够,需要进行页面置换,将内存中页面调出,调入新的页面
- 缺页中断:cpu访问某个页面,但此时这个页面未在内存中,这是会触发一个内中断(缺页终端),操作系统进入核心态,进程进入阻塞队列,开启io将页面调入内存,调入完毕,进程重新进入就绪队列,等待下次调用
局部性原理
- 时间局部性原理:现在访问到的指令,数据,很可能后面再次被用到。
- 空间局部性:现在访问的内存单元周围的内存空间,不久后也可能被访问到。
ecs是什么?
dots中的ecs为什么快?
- 拥有相同component的entity存储在一个chunk中,chunk中的数据连续存储,并且相同的component也连续存储,这样可以知道该chunk中存储本component的起始地址和终止地址(根据component的大小、数量和起始地址,可以计算出终止地址)。
- 对于system一般操作拥有某些组件的entity的集合,实际上也就是操作chunk中的component,根据局部性原理,对于连续存储的component,cpu在读取某个component的数据时,实际上会顺便读取它周围几个component的数据,保存在高速缓存中,下次再读取下一个component数据时,可以从高速缓存中查找(比从内存中快)。其实就是提高了cache命中率。
内存访问顺序
cpu寄存器,高速换存(一二三级,越来越慢),内存,硬盘。
排序和搜索
千万数据中的topn,大顶堆和小顶堆,时间复杂读为O(n)
dfs 和 bfs
红黑树和平衡二叉的区别
常用设计模式
设计原则
某个设计模式如何体现某个设计原则
垃圾回收算法,分代(C#),三色标记清除算法(lua)。
table实现
哈希冲突,dictionary实现
虚函数
无限滑动列表
gpuinstance原理,
将实例材质属性存储以结构数组的形式保存在constant buffer中,渲染时通过instance id去寻找相应的实例材质属性
批处理(静态合批,动态合批,srp,gpuinstance)
一些算法。
C# 和 lua交互。
UI canvasGroup 使用注意事项。
mipmap
il2cpp的引入
静态语言,动态语言,脚本语言,强类型语言,弱类型语言定义。
骨骼动画原理
-
Vworld = Vmesh * BoneOffsetMatrix1 * CombineMatrix1 * W1 +Vmesh * BoneOffsetMatrix2 * CombineMatrix2 * W2 +...+ Vmesh * BoneOffsetMatrixn * CombineMatrixn * Wn
-
BoneOffsetMatrix1 就是unity中的bindpos矩阵,将模型从模型空间转换到骨骼空间。
-
animationClip中记录的是当前骨骼点相当于父骨骼点的变换,(其中根骨骼的Transform Matrix是基于世界空间的转换,所以对于每一个下面的子骨骼,要计算其Transform Matrix,需要进行一个矩阵的连乘操作。最后得到的最终矩阵连乘结果矩阵就是Combined Transform Matrix,基于这个矩阵,就可以将顶点从骨骼所在的空间转换到世界空间中)。CombineMatrix = root_Transform_Matrix * father_root_transform_matrix * son_Transform_Matrix,其中root_Transform_Matrix是基于世界的,也就是基于模型空间的。root_Transform_Matrix * father_root_transform_matrix * son_Transform_Matrix * vertex(son空间中的顶点位置)。顶点连续左乘(第一次变换变换到father空间),最终变换到模型空间。而Vmesh * BoneOffsetMatrix_son(bindpos)正好可以将顶点变换到son空间
-
在骨骼动画中,每个动画数据中,会带来当前骨骼的新的变化(旋转为主),那么在当前动画数据的驱动下,当前骨骼变换到新的位置,得到新的骨骼矩阵,那么依附其上的顶点的位置也会变换,首先是将顶点位置从模型空间中转换到当前该骨骼的空间中,然后基于骨骼的当前这次变换矩阵(比如旋转90度对应的矩阵),得到其在该骨骼空间中的新位置,这个新的位置再和当前骨骼在和根骨骼的变换矩阵相作用,变换回模型空间中。
UI合批规则
- ui Rebuild:重新计算生成网格的过程,
- 是对一个Canvas来说的,Canvas可以嵌套,子Canvas的rebuild不会影响父Canvas和其他Canvas
- 对于一个Canvas合批时,首先从上到下遍历所有的UI元素,计算每个元素的depth,(不渲染为-1;遍历过的UI元素与当前不相交,则当前为0;遍历过的只有一个与当前相交,若能合批【材质和贴图相同】,则currentDepth = lowerDepth,否则currentDepth = lowerDepth + 1;若与多个ui相交,则找出最大的depth,如果只有一个元素的层是MaxLowerDepth,并且这个元素和CurrentUI的材质、纹理相同,那么它们就能合批,curentDepth = maxDepth,否则curentDepth = maxDepth + 1)
- 由于计算当前ui元素的深度时,需要遍历他之前所有的ui元素判断与其是否相交,所以时间复杂度为O(n*n),Unity 内部使用了分组的方式,将16个元素为一组,若当前元素与这16个元素组成的group的包围盒相交,在计算每个元素与其是否相交。相交是判断mesh是否相交
- 遍历完深度后,按照depth,materialId,textureId,RenderOrder(在Hierarchy上的顺序)由小到大排序。相邻两个元素,只要materialid,textureid相同就可以合批。
- 由于Canvas合拼是对于其下所有UI来说的,如果其中任何一个元素的材质、网格顶点、位置(Transform)甚至颜色或者在该Canvas下动态创建或删除UI元素都将导致该Canvas重新计算合批(需要注意的是仅仅会影响这一个Canvas,子Canvas或父Canvas以及其他Canvas不会重新计算)
这个图由于下面的button没和上面的text相交,所以,上面image depth 0,下面image能与上面合批,所以是0
;两个txt都是1,所以共两个batch