unity3D知识点随手记zblade

图集的本质,其实就是一张大图,将各个图集中的小图合并到一张大图,然后还有一份保存各个小图的尺寸、位置、偏移等信息的数据文件,所以一般一个图集会对应2个文件,当然如果把数据文件也打包进去,就会只有一个数据文件。

1)lua中table实现的原理

lua对于table的设计,是基于数组和hash共同兼容的,对于数组,其主要存储连续的同类型数据,hash则通过key-value的方式存储。对于hash和数组,默认大小都是0,然后是1,2,4等等基于2的幂次递增,由于每次递增的时候,都会进行一次rehash,所以性能都消耗在rehash上,所以在创建table的时候,尽量避免这样rehash的操作,比如:

localt1={}t["x"]=1,t["y"]=2,t["z"]=3,这样三次操作,就会触发三次rehash,想想原理即可明白

localt2={"x"=1,"y"=2,"z"=3},这样只会触发一次rehash,对比节省3次性能。

2)请回答lua中对于key值的查找过程

lua对于key值的查找,首先会去数组和hash中查找对应的key值,如果存在,则返回;如果不存在,则查找该table是否有元表metatable,如果没有,则返回nil;如果有,则查看metatable中是否有__index方法,如果没有,则返回nil;如果有,则执行__index[key]查找,返回对应的值。

3)lua如何执行GC,以及对应的原理和API设置

这儿做一个读后笔记记录吧:

(1)LuaGC对象

lua中一共有9种数据类型,分别为nil,boolean,lightuserdata,number,string,table,function,userdata和thread。其中,string,table,function,thread会被GC处理,此外还有proto和upvalue需要被GC处理。

(2)Lua数据定义方式union+type

//UnionofallLuavaluestypedefunion{GCObject*gc;void*p;lua_Numbern;intb;}Value;#defineTValuefieldsValuevalue;inttttypedefstructlua_TValue{TValuefields;}TValue所有的GCObject都有一个相同的数据头,CommonHeader,其定义为:

#defineCommonHeaderGCObject*next;lu_bytett;lu_bytemarked;这样所有的GCObject都会被同一个单向链表串接起来,每个对象基于tt识别,marked用来标记清除的工作

(3)Lua对不同类型的清除操作分类

Lua在每次GC清除的的时候,分为多种类型:

对于GCObject,通过若干根节点开始,逐个直接或者间接的将其上的所有节点左上标记,完成标记后,遍历链表,对未被标记的节点执行删除操作;

对于string类型,由于所有的string都放在一张大的hash表中,这样是为了确保整个lua中同一个string不会被创建两份,所以其是被单独管理的,不会被串在GCObject的链表中

对于upvalue类型数据,也是一个特殊处理过程,这是由于GC可能分布扫描,由于upvalue是对已有的对象的间接引用,在创建的时候不属于创建新数据,在mark的过程中需要添加luaC_barrier

对于userdata,由于userdata都有gc方法,所以会在最后单独处理逐一遍历所有的userdata来执行其中的gc方法,会有一些特殊的处理

(4)Lua执行GC的几个流程

Lua执行GC的几个流程,可以分为5步:GCSpause\GCSpropagate\GCSsweepstring\GCSsweep\GCSfinalize,从lua5.1开始就执行分布GC,每次执行可能会有多个状态切换

GCSpause为GC阶段的启动流程,标记系统的根节点即可

GCSpropagate这是标记流程,对尚未标记的对象(灰色链表)迭代标记(反复调用propagatemark),否则在atomic函数中执行一次标记

GCSsweepstring这就是前面提起的对string类型的数据,进行特殊的处理,在这个状态中,每步都会清除string的hash表中的一列

GCSsweep和上一个状态类是,不过这步操作的对象是GCObject

GCSfinalize在这儿主要对userdata执行,如果需要调用其gc,则执行gc操作,由于userdata的对象和关联数据不会在之前的清除阶段被清除,所以其实际清除会在下一次的GC清除中执行或者在lua_close中被清除:lua_close的工作就是简单的处理所有userdata的gc元方法,以及释放其所用到的内存。

(5)LuaGC的标记流程

Lua对于所有的GCObject都设置一个颜色,最开始是白色,新建的节点也是白色,然后在标记阶段,可见的节点被设置为黑色,如果某些节点关联其他节点,在没有处理完其关联节点前,都被标记为灰色,对于颜色的标记,其存储在CommonHeader的8位的marked域中,对于白色有两个白色的标记位,采用一种乒乓开关,避免在标记完成后,清理没有完成前,对象间关系发生变化的时候,某些不需要被清理的节点,就可以从一种类型的白色转换到另一种类型的白色中,比如当前删除0型白色,那么转换到1型白色,这样1型白色就会被保护起来不会被删除,反之亦然。具体对于8个位的定义和使用,可以看云风的原文,有一定讲解。

(6)LuaGC的操作

常用的几个API:luaC_fullgc\luaC_step\luaC_checkGC

luaC_fullgc:执行一次完整的gc动作,对于可能执行一般的流程,在走完一次流程后,会阻塞状态再次执行一遍gc,对于已经执行的前半程gc,其实不需要做清除操作,只需要做状态回复

luaC_step:其核心在与调用singlestep函数,通过设置gcstepmul值,可以设置步长,从而影响gcthreshold,其实步进量的设置,是一个经验值

luaC_checkGC:自动GC的接口,在大部分导致内存增长的api中会调用该方法,自动GC,可能会在某一个周期性中将众多临时对象也mark了,造成系统的峰值内存占用比实际需求大,可以在这种周期性调用中采用gcstep的方法,同时设置较大的data量,使得有限周期做一个完整的gc。

(7)LuaGC的mark操作

对于Lua的mark操作,主要操作的API:markroot\reallymarkobject\remarkupvals\atomic\iscleared

(8)LuaGC的writebarrier操作

主要的API:luaC_barrier\luaC_barriert\luaC_objbarrier\luaC_objbarriert

(9)LuaGC的剩余操作sweep/finalize

sweep的操作分为GCSsweepstring和GCSseep,贴2个源码:

caseGCSsweepstring:{lu_memold=g->totalbytes;sweepwholelist(L,&g->strt.hash[g->sweepstrgc++]);if(g->sweepstrgc>=g->strt.size)/*nothingmoretosweep*/g->gcstate=GCSsweep;/*endsweep-stringphase*/lua_assert(old>=g->totalbytes);g->estimate-=old-g->totalbytes;returnGCSWEEPCOST;}caseGCSsweep:{lu_memold=g->totalbytes;g->sweepgc=sweeplist(L,g->sweepgc,GCSWEEPMAX);if(*g->sweepgc==NULL){/*nothingmoretosweep*/checkSizes(L);g->gcstate=GCSfinalize;/*endsweepphase*/}lua_assert(old>=g->totalbytes);g->estimate-=old-g->totalbytes;returnGCSWEEPMAX*GCSWEEPCOST;}对于seeplist,其源代码为:

staticGCObject**sweeplist(lua_State*L,GCObject**p,lu_memcount){GCObject*curr;global_State*g=G(L);intdeadmask=otherwhite(g);while((curr=*p)!=NULL&&count-->0){if(curr->gch.tt==LUA_TTHREAD)/*sweepopenupvaluesofeachthread*/sweepwholelist(L,&gco2th(curr)->openupval);if((curr->gch.marked^WHITEBITS)&deadmask){/*notdead*/lua_assert(!isdead(g,curr)||testbit(curr->gch.marked,FIXEDBIT));makewhite(g,curr);/*makeitwhite(fornextcycle)*/p=&curr->gch.next;}else{/*musterase`curr'*/lua_assert(isdead(g,curr)||deadmask==bitmask(SFIXEDBIT));*p=curr->gch.next;if(curr==g->rootgc)/*isthefirstelementofthelist*/g->rootgc=curr->gch.next;/*adjustfirst*/freeobj(L,curr);}}returnp;}基本看源代码就可以理解,对于dead的freeobj,没有dead的则执行makewhite,最后一个流程就是GCSfinalize,通过GCTM函数执行,每次调用一个需要回收的userdata的gc元方法:

staticvoidGCTM(lua_State*L){global_State*g=G(L);GCObject*o=g->tmudata->gch.next;/*getfirstelement*/Udata*udata=rawgco2u(o);constTValue*tm;/*removeudatafrom`tmudata'*/if(o==g->tmudata)/*lastelement*/g->tmudata=NULL;elseg->tmudata->gch.next=udata->uv.next;udata->uv.next=g->mainthread->next;/*returnitto`root'list*/g->mainthread->next=o;makewhite(g,o);tm=fasttm(L,udata->uv.metatable,TM_GC);if(tm!=NULL){lu_byteoldah=L->allowhook;lu_memoldt=g->GCthreshold;L->allowhook=0;/*stopdebughooksduringGCtagmethod*/g->GCthreshold=2*g->totalbytes;/*avoidGCsteps*/setobj2s(L,L->top,tm);setuvalue(L,L->top+1,udata);L->top+=2;luaD_call(L,L->top-2,0);L->allowhook=oldah;/*restorehooks*/g->GCthreshold=oldt;/*restorethreshold*/}}在回收的时候,设置较大的GCthreshold来避免GC的重入

4、C#的GC原理和机制

1)使用内存托管的原因

(1)提高软件的开发速度(无需陷入内存管理中);(2)降低模块耦合,使得接口更清晰;(3)提高内存管理的效率;

2)GC的定义

garbagecollection,以应用程序的root为基础,遍历应用程序在堆上动态分配的所有对象,识别其是否被引用来确定其是否死亡还是被引用,对于不再引用的对象或者整个root,都标记为垃圾,然后执行回收。主要的算法有ReferenceCounting\MarkSweep\CopyCollection,目前主流的.NETCLR,JAVAVM都是采用MarkSweep的算法

3)MarkSweep-Compact算法

阶段1:Marksweep标记清除阶段,先假设heap中所有对象都可以回收,然后找出不能回收的对象,给这些对象打上标记,然后heap中没有被打标记的对象都是可以被回收的;

阶段2:compact阶段,对象回收之后heap内存空间变得不连续,在heap中移动这些对象,使得其从heap的基地址开始连续排列,类似于磁盘空间的碎片整理,然后将heap的指针指向压缩后的起始位置,便于下次内存分配;

操作流程:线程挂起->确定roots->创建reachableobjectsgraph->对象回收->heap压缩->指针修复

roots:就是CLR在heap之外可以找到的各个入口点,一般在全局变量、静态变量、局部对象、函数调用参数、当前CPU寄存器中的对象指针、finalizationqueue中,可以分为已经初始化了的静态变量、线程仍在使用的对象;

指针修复:由于heap的压缩,对象的地址发生变化,需要修复所有引用指针,包括stack\CPUregister中的指针\heap中其他对象的指针,copy原文中的图片:

4)Generational分代算法

分代算法,将对象按照生命周期分成新的、老的,根据统计分布规律所反应的结果,对新老区域采用不同的回收策略和算法,加快回收速度,其基本假设为:

(1)新创建的对象生命周期都较短,较老的对象生命周期会更长;

(2)对部分内存回收会比全内存回收更快;

(3)新创建的对象之间关联较强,内存分配是连续的,其基本操作如原文中图:

heap分为三个代,对应三种GC方式:#Gen0collection#Gen1collection#Gen2collection,对应的频率可以设置为1:10:100

5)FinalizationQueue\FreachableQueue

这两个队列会用来存储对象的指针,当程序中new一个对象创建在heap上,在GC的时候会对对象进行分析,如果其中含有Finalize方法,则会在FinalizationQueue中添加执行该对象的指针,在GC的时候,会将这个对象从垃圾中分离出来,然后将其从FinalizationQueue中移到FreachableQueue中,这个过程就是对象的复生。当被添加到FreachableQueue中后,就会触发对象执行Finalize方法,然后将指针从队列中移除,这时候整个对象可以安静的godie了。

System.GC类提供两个控制Finalize的方法,ReRegisterForFinalize和SuppressFinalize,前者请求系统完成对象的Finalize方法,后者请求系统不要完成对象的Finalize方法。

对于非托管的资源,主要采用Dispose方法来进行主动释放其中的托管和非托管资源,最后摘抄一下作者的总结:

GC注意事项:

1)只管理内存,非托管资源,如文件句柄,GDI资源,数据库连接等还需要用户去管理。

2)循环引用,网状结构等的实现会变得简单。GC的标志-压缩算法能有效的检测这些关系,并将不再被引用的网状结构整体删除。

3)GC通过从程序的根对象开始遍历来检测一个对象是否可被其他对象访问,而不是用类似于COM中的引用计数方法。

4)GC在一个独立的线程中运行来删除不再被引用的内存。

5)GC每次运行时会压缩托管堆。

6)你必须对非托管资源的释放负责。可以通过在类型中定义Finalizer来保证资源得到释放。

8)Finalizer的使用有性能上的代价。需要Finalization的对象不会立即被清除,而需要先执行Finalizer.Finalizer,不是在GC执行的线程被调用。GC把每一个需要执行Finalizer的对象放到一个队列中去,然后启动另一个线程来执行所有这些Finalizer,而GC线程继续去删除其他待回收的对象。在下一个GC周期,这些执行完Finalizer的对象的内存才会被回收。

9).NETGC使用"代"(generations)的概念来优化性能。代帮助GC更迅速的识别那些最可能成为垃圾的对象。在上次执行完垃圾回收后新创建的对象为第0代对象。经历了一次GC周期的对象为第1代对象。经历了两次或更多的GC周期的对象为第2代对象。代的作用是为了区分局部变量和需要在应用程序生存周期中一直存活的对象。大部分第0代对象是局部变量。成员变量和全局变量很快变成第1代对象并最终成为第2代对象。

5、unity中协程的理解

协程的本质是一个分部执行函数,在unity的mainThread中执行,unity在每帧的更新中,都会执行各个协程调用,分别在FixedUpdate和LateUpdate之后的一些协程调用上,其本质就是一个迭代器,当遇到条件不满足的时候会被挂起,条件满足的时候,会被唤醒来继续执行。举个在其他地方看到的例子吧,这样便于讲解过程:

voidStart(){StartCoroutine(Test1());}IEnumeratorTest1(){LogWrapper.Error("a1");yieldreturnTest2();LogWrapper.Error("a2");}IEnumeratorTest2(){LogWrapper.Error("b1");yieldreturnnull;LogWrapper.Error("b2");}

会输出什么的顺序:a1,b1,b2,a2

执行的顺序是先输出a1,然后执行Test2,输出b1,这时候遇到yieldreturnnull,被挂起,在下一帧,被唤醒,继续执行,输出b2,接着执行输出a2

如果对这个过程理解了,那么协程基本就没问题了

6、unity中meta文件的作用

有两个作用,第一是包含了当前资源(代码或者prefab,图片等)在当前工程中唯一的guid,unity获取资源是依据guid来获取的,所以每个资源都会附带生成一份meta文件;

7、unityUGUI的自适应方案设计

1)首先判断当前系统的平台,主要分为ios/android/PC三种主流平台;

2)针对不同的平台,读取不同的SystemInfo的参数来设置当前应该设置的renderLevel,具体的参数读取和判断,每个项目可能设置的不一样;

3)根据获取的renderLevel,再来设置当前Screen的width和height,renderLevel主要分为高,中,低三个档次

4)对于高中低三个档次,分别不同的处理,

高,直接将当前屏幕的width和height设置为最终的width/height;

中,则根据当前读取的屏幕的height来做不同的设置

低,则将当前屏幕的width/height减半;

对于中低两个档次的设置,最后还需要执行一次adjust,避免width低于最低width,然后对比初始width/height和计算后的width/height的比值大小,做对应的width或者height的调整;

最后,都调用Screen.SetResolution(width,height,Screen.fullScreen)这个接口来实现自适应的匹配

8、c#的虚函数的调用

摘用作者的几句话,详尽的解释了虚函数的特点和执行过程:

虚函数的特点:

虚函数前不允许有static\abstract\override等修饰字,不能私有(private不能有)

虚函数的执行:

一般函数在编译时期就静态的编译到执行文件中,其相对地址在程序运行期间是不会发生变化的;

虚函数在编译期间不被静态编译,其相对地址不确定,而是根据运行时期对象实例来动态判断要调用的函数。

1)当调用一个对象的函数时,首先检测该对象的申明类,看该方法是否为虚函数;

2)如果不为虚函数,则直接执行该函数,如果为虚函数,则检测该对象的实例类;

3)检测实例类中是否有实现该虚函数或者重新实现该虚函数(override),如果有,则执行该虚函数,否则继续查找该实例的父类,知道找到第一个重载或者实现了该虚函数的地方,执行该虚函数。

THE END
1.「中移在线工资待遇怎么样」中移在线服务有限公司薪酬福利加班情况中移在线需要什么学历?本科占比最多,占91.7%,硕士占7%,大专占1.2% 中移在线工资按学历统计 大专¥5.3K 本科 硕士 说明:中移在线工资按学历统计,大专工资¥5.3K,想知道其他学历工资,请点击详细页查看 中移在线硕士工资待遇(更多) 中移在线硕士工资:86.9%的人拿¥15-50K https://www.jobui.com/company/12241153/salary/
2.基于多层结构的网络游戏平台的研究与应用现在,快速以太网、千兆以太骨干网基础和高性能、高可靠性的服务器已经成为网络游 戏网络运营的核心,三层和多层软件体系结构以及集群技术的逐步成熟,使得网络游戏平台 的研究和开发完全成为可能,并能满足几十万用户同时在线。其中,集群技术是随着计算机 在社会生活的各个层次广泛应用近年来迅速发展、壮大起来的一个软件领域https://blog.csdn.net/weixin_30664051/article/details/94814364
3.中移铁通社会招聘试题20221011205543.pdf中移铁通社会招聘试题.pdf,中移铁通社会招聘试题 2022/10/11 中移铁通社会招聘试题 一、第一部分 言语理解与表达 (本部分包括表达与理解两方面的 容。请根据题 目要求,在四个选项中选出一个最恰当的答案。) 1、微软前技术总监纳森·梅尔沃德2001年组建“ 智力风险”公司https://m.book118.com/html/2022/1011/8142075035005002.shtm
4.朗诗德家用净水器属于什么档次?上百项专利证书,朗诗德净水器不断朗诗德净水器是一线净水器品牌之一,专业致力于健康饮水设备的设计、开发、生产。其产品超滤直饮水、管线直饮水机、公共直饮机等适用于不同市场需求,确保饮水方法更加安全、健康、环保、快捷。那么朗诗德家用净水器属于什么档次?朗诗德净水器是行业内大品牌,其品牌知名度和美誉度在不断上升,是值得消费者信任的品牌。 https://www.chinajsq.cn/zhishi/166217.html
5.石英质玉的档次分类石英质玉属于什么档次 石英质玉是一种非常受欢迎的宝石,它兼具美观和价值。石英质玉属于中档至高档的宝石。 石英质玉的颜色是其档次的一个必不可少指标。石英质玉可有多种颜色,涵盖绿色、紫色、黄色和透明。其中,颜色越纯净、饱满,档次越高。比较常见的是绿色玉石,其中绿色越饱和玉石优劣越高。在市场上,色彩鲜艳https://www.jqcom.cn/2024baiqi/fcyushi/932937.html
6.中移VONR语数分层策略,一般情况下是把VONR用户迁移至哪个频段?网络反腐的成效被形象地称为“小鼠标绊倒大贪官”。网上举报拥有速度快、影响大和低成本、低风险等特点已经受到网民的空前欢迎,但同时也应看到,网络反腐的信息缺乏权威引导,很多信息未得证实便在网上泛滥,往往对他人造成无谓的困扰,也会淡化人们的法律意识。对此,下列认识正确的是 ①网络监督是公民行使监督https://www.shuashuati.com/ti/f1df817f61f14f0eb82dd117acff8338.html?fm=bd988ee792a640a76d20bc0e418d0eb8ff
7.逆转思维第五篇生意好不好,不在努力在思路在线免费阅读此时,你不妨反过来思索,把焦点暂时从热闹的股市中移开,转向一个人,他就是庄家。猜猜看,庄家最怕什么?告诉你,庄家最怕你不看他!因为庄家深知你的贪婪与恐惧,利用你这类中小散户的弱点,与你对着干。庄家的阴谋会通过操盘手传递给你,明明股票要起动,却一路凶杀,你不抛出,他决不会停止;明明要出货,却拼命放量拉抬https://fanqienovel.com/reader/7308968139801234494
8.中移微小店优选号卡 39元动感地带潮玩卡40GB定向+30GB通用流量+全国亲情网互打免费¥39.00起 去查看 ¥39.00起 万能副卡 10元/月,主卡代付,共享主卡套餐内流量和语音分钟数 ¥10.00起 权益+流量 7折享20元小福券半年可领12元立减金或15元美团外卖券,首月可享8GB¥14.00 http://dx.10086.cn/e9xQFA
9.物联网人眼中的2018,是寒冬深入还是阳春将至?中移物联网有限公司运营总监 龚勇 目前多款NB模组价格处于20元价位段。据我们预测:19年NB和4G模组将出现大爆发,NB和4G价格会进一步下调,NB模组将全面下调到20元以内,4G将下调到80元以内,2G存量客户在一两年内会逐步升级到NB、eMTC、4G。并且随着模组市场的成本压力增大,利润空间越来越小,预计模组行业会重新洗牌,落https://www.iyiou.com/news/2018123188938
10.CBHN测试38. 以下哪个产品不属于互联网公司的产品 和彩云 和留言 游戏加速 视频彩铃 39. 以下不属于个人业务资料范围 业务受理单 身份证明材料 电话录音 人脸照片 40. 基础产品融合套餐中,高档次套餐要靠()形成价值区隔突出 流量 权益 语音 套外流量 41. 通过应用电子签名等技术手段实现电子文件的形式存储业务工单,逐步取https://www.wjx.cn/vm/OUGTmut.aspx
11.元岗长湴村招标!天河做地旧改,飙起来了房产资讯对于天河跑起来的做地旧改,你又是怎么看的? 直播预告: 365天住酒店,什么档次? 10月24日周四中午11:00,主播带你探秘越秀区首个酒店式地标奢宅,看它的顶流之路如何炼成的! 还有微波炉、电烤炉等家电抽奖等你来~赶紧点击下方预约直播吧~https://news.fang.com/open/51391123.html
12.banner_id=cmyj-ly117 ,在线就可以购买,购买后30分钟内收到了电子保单。电子保单彩色打印第一页后可用于办理签证,保单为中英文对照。根据签证实际情况,建议提前准备一份保单复印件给使馆备份。注意:保单的生效日期各大使馆要求不同。@广州 使馆要求前后行程多买2天,闺蜜在@上海 使馆递签是在行程后面加5天。https://itf.mafengwo.cn/client/note.php/info/?id=2921078