记录¶
面试 socket整理一下资料 fin ,rst包分别在什么时候发 Linger=true为啥close(0)发rst包
断线重连
zlib,loom,sevenlib,ngui,a*,fingergesture,t4m,besthttp,itween,dotween,uniwebview,easytouch,meshbaker,spine,minijson
贴图压缩(在屏幕显示范围大的不压缩,显示小的压缩)
assetbundle压缩(BuildAssetBundleOptions.ChunkBasedCompression)
assetbundle压缩比例 lzma 4倍,lz4 3倍
navigation寻路(性能测试)
a*寻路
5.3.2动画问题 动态加载烘培问题
assetbundle --资源卸载(Resources.UnloadUnusedAssets() 异步) --AssetBundle.LoadFromMemory() 加载比较慢
ui适配 等比缩放 NGUi: Flexible:这样方式保存的场景和控件大小是固定的,如果你设置的像素值为300*200那么在屏幕比较小的设备上,它会显的比较大;屏幕比较大的设备上会显得比较小;其实就是大小不会根据屏幕大小变化而变化。这个不符合我们屏幕自适应的要求,应该也不会常用。 Constrained:这个与上面那种方式是完全相反的,他不会固定一个值,而是随着设备屏幕大小的变化而变化,大小是依据百分比,但是要注意,在根据百分比缩放的同时 画面有可能会失真。 ConstrainedOnMobiles:这个我没太理解,大概意思应该是在桌面设备上它会以 Flexible 的方式进行显示,如果是移动设备的话它将以 Constrained 的方式显示。
aspect(宽高比) standardAspect=1280/720=1.78 aspect1=1.3 aspect2=1.8 aspect1<standardAspect<aspect2 ---适配高度 aspect1:高度太大,适配高度后,宽方向ui出去了 。所以适配宽度方向(unity可以调整Camera的size=standardAspect/aspect1,在standardAspect时 size=1。这样等于适配宽度方向,高度有黑边然后把高度方向的背景图做大1280*960,aspect=1.3,一般没有小于1.3得了) aspect2:宽度太大,适配高度后,宽方向ui有黑边 (但是一般没有大于1.7的比例了) ---适配宽度 aspect1:高度太大,适配宽度后,高方向ui有黑边 aspect2:宽度太大,适配宽度后,高方向ui出去了
etc etc2
fbx 的read/write 可以关闭 但是粒子特效的mesh需要打开,粒子系统通常需要动态地修改其粒子的顶点属性 ,将FBX上的Read/Write Enabled关闭后,内存中便不再保存其Mesh的副本(只存在显存中),因此其属性就不可再被访问和修改。
=> 拉姆达表达式
断点续传
正则表达式 平衡组/递归匹配 固化分组 (几层括号嵌套);@"{([^{}]+|{(?
ftp C#工程ftp上传没问题,unity工程里面上传失败(ftp 的socket 没有优雅的关闭,先shutdown 再 close 注意有个选项Linger 有数据是否在关闭时逗留 )
打包删除场景,进入场景怎么进去的??
MemoryStream 在调用Close()和Dispose()后 仍然可以使用ToArray()获取数据的字节数组
Finalize Dispose Close 用于非托管资源 ,其它时候没有意义 http://www.cnblogs.com/liuning8023/archive/2012/07/22/2603819.html ---Finalize方法(C#中是析构函数,以下称析构函数)是用于释放非托管资源的,而托管资源会由GC自动回收。 ---Finalize 在C#中就是指析构函数,该方法默认存在,只有在定义析构函数后在析构函数中会隐式的调用Finalize,只有定义析构函数后终结器才能看到Finalize或者析构函数 您无法从 C# 或 C++ 编程语言的托管扩展中调用或重写 Object.Finalize 方法。C# 和托管扩展提供析构函数作为编写终止代码的机制。在 C# 和托管扩展中,您必须使用析构函数语法来执行清理操作。因为该语法隐式地为对象基类调用 Finalize 方法,所以十分方便易用。这保证了对当前类从其导出的所有级别的析构函数都调用了 Finalize。 ---Dispose 只是用于显式的释放对象,在Dispose中默认会先调用Close,dispose是主动释放,一般用using语法可以代为实现 ---using语句块执行完默认会执行Dispose ---GC.SuppressFinalize(this); 这个方法是被客户直接调用的,告诉垃圾回收器从Finalization队列中清除自己,从而阻止垃圾回收器调用 析构函数 方法 ---在.net framework 里面,close()被设计成public的,并且在close()里面调用被隐藏的dispose(),而后dispose()再去调用另一个virtual的dispose(bool)
终结器(Finalize方法): 垃圾回收器使用名为“终止队列”的内部结构跟踪具有 Finalize 方法的对象。每次您的应用程序创建具有 Finalize 方法的对象时,垃圾回收器都在终止队列中放置一个指向该对象的项。托管堆中所有需要在垃圾回收器回收其内存之前调用它们的终止代码的对象都在终止队列中含有项。(实现Finalize方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。用Finalize方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用Finalize方法,然后将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。概括而言,就是将垃圾回收分为了三个阶段,第一个阶段回收没有Finalize方法或者析构函数的对象,第二个阶段调用那些析构函数或者Finalize方法,第三个阶段回收那些刚调用了析构函数或者Finalize方法的对象。)
终结器(finalizer)是在回收过程中,由垃圾回收器调用的方法。如何含有终结器的对象到了G2中,那么就会需要非常长的时间来回收。事实上,根据应用程序运行时间的长短,对象很有机会直到应用程序退出之前都不会被回收(特别是其中包含的重要的资源得不得释放,将会对性能产生很大的影响,比如说数据库连接得不到释放。)
实现模型: 1、由于大多数的非托管资源都要求可以手动释放,所以,我们应该专门为释放非托管资源公开一个方法。实现IDispose接口的Dispose方法是最好的模型,因为C#支持using语句快,可以在离开语句块时自动调用Dispose方法。 2、虽然可以手动释放非托管资源,我们仍然要在析构函数中释放非托管资源,这样才是安全的应用程序。否则如果因为程序员的疏忽忘记了手动释放非托管资源, 那么就会带来灾难性的后果。所以说在析构函数中释放非托管资源,是一种补救的措施,至少对于大多数类来说是如此。 3、由于析构函数的调用将导致GC对对象回收的效率降低,所以如果已经完成了析构函数该干的事情(例如释放非托管资源),就应当使用SuppressFinalize方法告诉GC不需要再执行某个对象的析构函数。 4、析构函数中只能释放非托管资源而不能对任何托管的对象/资源进行操作。因为你无法预测析构函数的运行时机,所以,当析构函数被执行的时候,也许你进行操作的托管资源已经被释放了。这样将导致严重的后果。 5、(这是一个规则)如果一个类拥有一个实现了IDispose接口类型的成员,并创建(注意是创建,而不是接收,必须是由类自己创建)它的实例对象,则 这个类也应该实现IDispose接口,并在Dispose方法中调用所有实现了IDispose接口的成员的Dispose方法。 只有这样的才能保证所有实现了IDispose接口的类的对象的Dispose方法能够被调用到,确保可以手动释放任何需要释放的资源。
Finalize()特性:
重写Finalize()的唯一原因是,c#类通过PInvoke或复杂的COM互操作性任务使用了非托管资源(典型的情况是通过System.Runtime.InteropServices.Marshal类型定义的各成员)注:PInvoke是平台调用服务。 object中有finalize方法,但创建的类不能重写此方法,若Overide会报错,只能通过析构函数来达到同样的效果。 Finalize方法的作用是保证.NET对象能在垃圾回收时清除非托管资源。 在CLR在托管堆上分配对象时,运行库自动确定该对象是否提供一个自定义的Finalize方法。如果是这样,对象会被标记为可终结的,同时一个指向这个对象的指针被保存在名为终结队列的内部队列中。终结队列是一个由垃圾回收器维护的表,它指向每一个在从堆上删除之前必须被终结的对象。 注意:Finalize虽然看似手动清除非托管资源,其实还是由垃圾回收器维护,它的最大作用是确保非托管资源一定被释放。 在结构上重写Finalize是不合法的,因为结构是值类型,不在堆上,Finalize是垃圾回收器调用来清理托管堆的,而结构不在堆上。 Dispose()特性:
为了更快更具操作性进行释放,而非让垃圾回收器(即不可预知)来进行,可以使用Dispose,即实现IDispose接口. 结构和类类型都可以实现IDispose(与重写Finalize不同,Finalize只适用于类类型),因为不是垃圾回收器来调用Dispose方法,而是对象本身释放非托管资源,如Car.Dispose().如果编码时没有调用Dispose方法,以为着非托管资源永远得不到释放。 如果对象支持IDisposable,总是要对任何直接创建的对象调用Dispose(),即有实现IDisposable接口的类对象都必须调用Dispose方法。应该认为,如果类设计者选择支持Dispose方法,这个类型就需要执行清除工作。记住一点,如果类型实现了IDisposable接口,调用Dispose方法总是正确的。 .net基类库中许多类型都实现IDisposable接口,并使用了Dispose的别名,其中一个别名如IO中的Close方法,等等别名。使得看起来更自然。 using关键字,实际内部也是实现IDisposable方法,用ildasm.exe查看使用了using的代码的CIL,会发现是用try/finally去包含using中的代码,并且在finally中调用dispose方法。 个人总结:
相同点:
都是为了确保非托管资源得到释放。 不同点:
finalize由垃圾回收器调用;dispose由对象调用。 finalize无需担心因为没有调用finalize而使非托管资源得不到释放,而dispose必须手动调用。 finalize虽然无需担心因为没有调用finalize而使非托管资源得不到释放,但因为由垃圾回收器管理,不能保证立即释放非托管资源;而dispose一调用便释放非托管资源。 只有类类型才能重写finalize,而结构不能;类和结构都能实现IDispose.原因请看Finalize()特性。
class Car
{
///
}
}
该析构函数隐式调用对象基类的 Finalize 方法。因此,该析构函数被隐式地转换为如下代码:
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
这意味着,对继承链中的所有实例递归调用 Finalize 方法。
说明:不要使用空的析构函数。如果类包含析构函数,则 Finalize 队列中则会创建一个项。当调用析构函数时,将调用垃圾回收器(GC)来处理该队列。如果析构函数为空,只会导致不必要的性能损失。
Object.Finalize 方法
允许 Object 在“垃圾回收”回收 Object 之前,尝试释放资源并执行其他清理操作。Finalize 是受保护的,因此只能通过此类或派生类访问它。
对象变为不可访问后,将自动调用此方法,除非已通过 GC.SuppressFinalize 调用使对象免除了终结。在应用程序域的关闭过程中,对没有免除终结的对象将自动调用 Finalize,即使那些对象仍是可访问的。对于给定的实例仅自动调用 Finalize 一次,除非使用 GC.ReRegisterForFinalize重新注册该对象,并且后面没有调用 GC.SuppressFinalize。
派生类型中的每个 Finalize 实现都必须调用其基类型的 Finalize 实现。这是唯一一种允许应用程序代码调用 Finalize 的情况。
注意:C# 编译器不允许你直接实现 Finalize 方法,因此 C# 析构函数自动调用其基类的析构函数。
Finalize 操作具有下列限制:
1) 垃圾回收过程中执行终结器的准确时间是不确定的。不保证资源在任何特定的时间都能释放,除非调用 Close 方法或 Dispose 方法。
2) 即使一个对象引用另一个对象,也不能保证两个对象的终结器以任何特定的顺序运行。即,如果对象 A 具有对对象 B 的引用,并且两者都有终结器,则当对象 A 的终结器启动时,对象 B 可能已经终结了。
3) 运行终结器的线程是未指定的。
在下面的异常情况下,Finalize 方法可能不会运行完成或可能根本不运行:
1) 另一个终结器无限期地阻止(进入无限循环,试图获取永远无法获取的锁,诸如此类)。由于运行时试图运行终结器来完成,所以如果一个终结器无限期地阻止,则可能不会调用其他终结器。
2) 进程终止,但不给运行时提供清理的机会。在这种情况下,运行时的第一个进程终止通知是 DLL_PROCESS_DETACH 通知。
在关闭过程中,只有当可终结对象的数目继续减少时,运行时才继续 Finalize 对象。
如果 Finalize 或 Finalize 的重写引发异常,并且运行库并非寄宿在重写默认策略的应用程序中,则运行库将终止进程,并且不执行任何活动的 try-finally 块或终结器。如果终结器无法释放或销毁资源,此行为可以确保进程完整性。
说明:默认情况下,Object.Finalize 不执行任何操作。只有在必要时才必须由派生类重写它,因为如果必须运行 Finalize 操作,垃圾回收过程中的回收往往需要长得多的时间。如果 Object 保存了对任何资源的引用,则 Finalize 必须由派生类重写,以便在垃圾回收过程中,在放弃 Object 之前释放这些资源。当类型使用文件句柄或数据库连接这类在回收使用托管对象时必须释放的非托管资源时,该类型必须实现 Finalize。Finalize 可以采取任何操作,包括在垃圾回收过程中清理了对象后使对象复活(即,使对象再次可访问)。但是,对象只能复活一次;在垃圾回收过程中,不能对复活对象调用 Finalize。
析构函数是执行清理操作的 C# 机制。析构函数提供了适当的保护措施,如自动调用基类型的析构函数。在 C# 代码中,不能调用或重写 Object.Finalize。
析构函数和Finalize不能同时存在一个类的定义中 假设有三个类 A->B->C;C继承B,B继承A A有析构函数,C有析构函数 B有Finalize方法 创建C一个实例查看析构情况 protected void Finalize(){...} C B执行 protected virtual void Finalize(){...} A执行 public void Finalize(){...} A C执行 public virtual void Finalize(){...} 运行直接崩溃(都没有执行) private void Finalize(){...} A C执行 private virtual void Finalize() 编译错误(虚拟成员或抽象成员不能是私有的)
如果把 Finalize写在C中 AB的析构执行 C的Finalize不执行 base.Finalize() 调用必须父类中有Finalize定义(父类用析构不行,编译报错,Finalize方法不存在)
MemoryStream Position重置为0 但是 Length 不变 Length和Position没有必然关系
封箱和拆箱 ---装箱在值类型向引用类型转换时发生 ---拆箱在引用类型向值类型转换时发生
List,IList,Array,ArrayList
蒙皮网格原理
哈希算法
动画融合
a*算法
设计模式
ui上的粒子特效
Navigation寻路 -------加速度控制不方便 不能为0,可以设置Vector3的速度变量 -------不能取寻路数据的高度值 -------OffMeshLink手动控制路径,一次只能通过一个agent,如果有agent正在通过OffMeshLink路径,其他agent只能在入口等着 不能通过
C# WebRequest 超时bug 21秒左右
C# http ServicePointManager.Expect100Continue = false; -----100-continue用于客户端在发送POST数据给服务器前,征询服务器情况,看服务器是否处理POST的数据,如果不处理,客户端则不上传POST数据,如果处理,则POST上传数据。在现实应用中,通过在POST大数据时,才会使用100-continue协议。
socket shutdown和close的区别,除了Fork进程引用计数之外还有什么 FTP上传文件后必须用ShutDown(如果设置了Linger为ture)
UTF-8, UTF-16, UTF-16LE, UTF-16BE的区别(UTF-16LE 在C#里面是Encoding.unicode) 首先, 我们说的unicode, 其实就是utf-16, 但最通用的却是utf-8, 原因: 我猜大概是英文占的比例比较大, 这样utf-8的存储优势比较明显, 因为utf-16是固定16位的(双字节), 而utf-8则是看情况而定, 即可变长度, 常规的128个ASCII只需要8位(单字节), 而汉字需要24位 UTF-16, UTF-16LE, UTF-16BE, 及其区别BOM 同样都是unicode, 为什么要搞3种这么麻烦? 先说UTF-16BE (big endian), 比较好理解的, 俗称大头,比如说char 'a', ascii为0x61; 那么它的utf-8, 则为 [0x61], 但utf-16是16位的, 所以为[0x00, 0x61];再说UTF-16LE(little endian), 俗称小头, 这个是比较常用的 .还是char'a', 它的代码却反过来: [0x61, 0x00], 据说是为了提高速度而迎合CPU的胃口, CPU就是这到倒着吃数据的, 这里面有汇编的知识, 不多说 然后说UTF-16, 要从代码里自动判断一个文件到底是UTF-16LE还是BE, 对于单纯的英文字符来说还比较好办, 但要有特殊字符, 图形符号, 汉字, 法文, 俄语, 火星语之类的话, 相信各位都很头痛吧, 所以, unicode组织引入了BOM的概念, 即byte order mark, 顾名思义, 就是表名这个文件到底是LE还是BE的, 其方法就是, 在UTF-16文件的头2个字节里做个标记: LE [0xFF, 0xFE], BE [0xFE, 0xFF]
理解了这个后, 在java里遇到utf-16还是会遇到麻烦, 因为要在文件里面单独判断头2个再字节是很不流畅的 InputStreamReader reader=new InputStreamReader(fin, charset) (Java代码) 1. 如果这个UTF-16文件里带有BOM的话, charset就用"UTF-16", java会自动根据BOM判断LE还是BE, 如果你在这里指定了"UTF-16LE"或"UTF-16BE"的话, 猜错了会生成乱七八糟的文件, 哪怕猜对了, java也会把头2个字节当成文本输出给你而不会略过去, 因为[FF FE]或[FE FF]这2个代码没有内容, 所以, windows会用"?"代替给你 2. 如果这个UTF-16文件里不带BOM的话, 则charset就要用"UTF-16LE"或"UTF-16BE"来指定LE还是BE的编码方式 另外, UTF-8也有BOM的, [0xEF, 0xBB, 0xBF], 但可有可无, 但用windows的notepad另存为时会自动帮你加上这个, 而很多非windows平台的UTF8文件又没有这个BOM, 真是难为我们这些程序员啊 http://www.iteye.com/topic/583064