项目组内有一台打包机,老是出错。
经常出现 OutOfMemoryExceptoin,百思不得其解。
今天再仔细推敲了代码后,发现原来的字典长度写的是 dictionary = 1 << 23;
修改为如下图后,没有再次出现过OutOfMemoryException。
项目组内有一台打包机,老是出错。
经常出现 OutOfMemoryExceptoin,百思不得其解。
今天再仔细推敲了代码后,发现原来的字典长度写的是 dictionary = 1 << 23;
修改为如下图后,没有再次出现过OutOfMemoryException。
ios号sigpipe会导致app被杀死。
因此需要对sigpipe进行屏蔽。
signal(SIGPIPE, SIG_IGN)
如果连xcode进行调试,还会继续捕获sigpipe,但不影响app,点击继续即可。
测试目的:
测试异常在android及ios64下的表现,查看是否导致闪退或崩溃。
测试代码:
private void onclick1( ){ Debug.Log("click1"); int m=3; int n=0; Debug.Log(m/n); } private void onclick2( ){ Debug.Log("click2"); TestA test=null; Debug.Log(test.m); }
在unity editor中:
表现正常,没有导致app死掉。
在Android中:
可以在ddms中收集到异常,同时app没有崩溃。
在IOS中:
也是可以正常打出log及堆栈
发现也没有引起崩溃。
IOS上32位mono闪退的原因找到了:
解决方案:
http://developer.xamarin.com/guides/ios/troubleshooting/troubleshooting/
基本上有几种方式
1、DateTime.UtcNow,性能好,速度快,但是精度低一此,10ms左右
2、第二种是用StopWatch,但是据称在多核多线程环境会有时有误差。
3、Process.GetCurrentProcess().TotalProcessorTime;时间准确度高,但相应的是性能较低下。可以使用宏定义,在测试版本中才开启,在正式发布版本中关闭这个功能。
噢,我们用时间,主要是用来埋点查看性能热点的地方。
以前解决一个加载慢的问题时,发现fmod写的加载代码很差,尤其在android平台,做了很多无用功。
于是我就重写了fmod加载代码,使用www异步加载,加载的字节数组放在cache中,然后供fmod调用:
FMOD.RESULT result = FMOD_StudioSystem.sInstance.System.loadBankMemory(pair.Value,LOAD_BANK_FLAGS.NORMAL,out bank);
结果发现在ios上无法播放声音。
开始怀疑过il2cpp的问题,但是没有log,不能随便下定论。
添加过很多log后,定位到上面的函数出问题了,但是log中只记录执行到这里就没了。没有输出为什么错。
丝毫没有头绪后,在fmod官方发现有新版本了,下载新版本后,测试下,发现还是没有声音,但是至少有异常log了。
il2cpp暂时不支持从c/c++对c#进行调用,或者说至少不支持现在fmod的用法。
解决方法也很简单,修改为使用
FMOD.RESULT result = FMOD_StudioSystem.instance.System.loadBankFile(bankPath, LOAD_BANK_FLAGS.NORMAL, out bank);
网上还有一个哥们遇到同样问题了,关注下看看他怎么解决。
http://forum.unity3d.com/threads/making-calls-from-c-to-c-with-il2cpp-instead-of-mono_runtime_invoke.295697/
http://forum.unity3d.com/threads/pinvoke-mono_add_internal_call-c-and-c.172886/
以备自己学习用。
这里还有一篇:http://www.snowbolt.com/index.php/blog/28-tech/91-pinvoke
目前看起来,mono要比c/c++慢一个数量级,lua又比mono慢一个数量级。
如果想要最好的性能,应该还是lua直接建在c/c++上,但是又如何去调用MonoBehaviour,如果能跳过mono,直接通过c/c++调用,则性能应该是最优的。但是需要确认下如何调用?
如果能实现,则是c/c++ + lua,直接跳过了 mono。
还有不确定的因素:il2cpp会不会可以直接实现这些性能提升?未来 需要确认下。
网上有位兄弟反编译的unity editor,看了下,不知道能否实现 lua 直接像调用c接口一样来调用MonoBehaviour.
namespace UnityEngine { using System; using System.Collections; using System.Runtime.CompilerServices; public class MonoBehaviour : Behaviour { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] public extern MonoBehaviour(); public void CancelInvoke() { this.Internal_CancelInvokeAll(); } [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] public extern void CancelInvoke(string methodName); [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] private extern void Internal_CancelInvokeAll(); [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] private extern bool Internal_IsInvokingAll(); [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] public extern void Invoke(string methodName, float time); [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] public extern void InvokeRepeating(string methodName, float time, float repeatRate); public bool IsInvoking() { return this.Internal_IsInvokingAll(); } [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] public extern bool IsInvoking(string methodName); public static void print(object message) { Debug.Log(message); } public Coroutine StartCoroutine(IEnumerator routine) { return this.StartCoroutine_Auto(routine); } public Coroutine StartCoroutine(string methodName) { object obj2 = null; return this.StartCoroutine(methodName, obj2); } [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] public extern Coroutine StartCoroutine(string methodName, object value); [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] public extern Coroutine StartCoroutine_Auto(IEnumerator routine); [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] public extern void StopAllCoroutines(); [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] public extern void StopCoroutine(string methodName); public bool useGUILayout { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] set; } } }
大计算量的代码,尽量避免使用c#代码,能用c/c++实现,就使用c/c++实现,然后暴露接口给c#层使用。
IEnumerator test1(){ String filePath1=Application.streamingAssetsPath+"/Boss.bank"; String filePath2="file:///"+Application.streamingAssetsPath+"/Boss.bank"; String filePath3=System.IO.Path.Combine(Application.streamingAssetsPath,"/Boss.bank"); String filePath4=System.IO.Path.Combine(Application.streamingAssetsPath,"Boss.bank"); textbox1.label.text=filePath1+"\n\n"+filePath2+"\n\n"+filePath3+"\n\n"+filePath4+"\n\n"; textbox1.label.text+=File.Exists(filePath1)+"\n"; textbox1.label.text+=File.Exists(filePath2)+"\n"; textbox1.label.text+=File.Exists(filePath3)+"\n"; textbox1.label.text+=File.Exists(filePath4)+"\n"; WWW www1=new WWW(filePath1); yield return www1; WWW www2=new WWW(filePath2); yield return www2; WWW www3=new WWW(filePath3); yield return www3; WWW www4=new WWW(filePath4); yield return www4; textbox1.label.text+=www1.bytesDownloaded+" "+www1.error+"\n"; textbox1.label.text+=www2.bytesDownloaded+" "+www2.error+"\n"; textbox1.label.text+=www3.bytesDownloaded+" "+www3.error+"\n"; textbox1.label.text+=www4.bytesDownloaded+" "+www4.error+"\n"; }
PC 运行如图:
android手机运行如图:
如果在unity中取文件:
string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "csv/"+configName); byte[] result=null; if (filePath.Contains("://")) { WWW www = new WWW(filePath); yield return www; while(!www.isDone()){ yield return null; } result = www.bytes; } else { result = System.IO.File.ReadAllBytes(filePath); }
如果在unity中想全部用www取文件
string filePath3 = Application.streamingAssetsPath + "/bt2/android/"; if (!filePath3.Contains("://")) { filePath3 = "file:///" + filePath3; }
在android下需要注意,因为apk本身是压缩格式,无法直接用File取文件,必须用www取文件。
用www取文件注意格式,一定要等www.isDone
接上一重篇:
上次修改完成后,配置加载已经非常快了, 但发现了另外一个现象,在检查配置更新时会卡上约6秒左右。
检查更新做的事情很简单,就是去网上请求一个静态文件,这里为什么卡成这样。
添加了一些埋点代码记录运行的时间后发现,卡在了加载音频那里,游戏中的音频有30M,而且那里是同步加载 -.-!! ,现在需要对音频进行拆分,
1、一部分需要在登陆前加载,比如UI上绑定的音频之类(按钮声)
2、一部分需要在战斗前加载成功,比如战斗中的音频
3、一部分需要异步加载,比如背景音乐之类
4、一部分只需要用时再加载,用完立即释放掉,比如人物对话音频之类。
另外在splash image后第一个场景需要update执行完后才会显示出来,因此有些非常耗时的操作避免在第一次update时执行。
我们游戏中第一次运行中,会下载配置表并进行加载。
但是我们发现一个现象:
第一次下载后,会在加载那里卡5秒左右。而以后再也不会遇到相同的卡的状况。
花了些时间发现了原因是c#代码导致的。
我们配置表使用csv,第一次下载后通过www类可以拿到下载的byte[],想避免一次IO操作,就使用c#写了解析为字符串数组的代码。
而非第一次下载,则使用File.ReadAllLine直接从文件中读取。
原来写时,以为能避免一次IO操作,可以提高性能,这里不能不说,C#自带的函数(底层使用c/c++实现),要远比c#的代码速度快的多。
也有可能是我写的C#代码太烂了的原因。
烂代码大家可以了解下:就是被注释掉的代码引导的卡。
string[] allDatas = null; /* if (doneList != null) { for (int m = 0; m < doneList.Count; m++) { ConfigFile cf = doneList[m]; if (cf.configName.Equals(configName+".bin")) { Debug.Log("Time1 :"+Time.realtimeSinceStartup); StringReader sr = new StringReader(UTF8Encoding.UTF8.GetString(cf.content)); List<string> list = new List<string>(); string str = null; while ((str = sr.ReadLine()) != null) { list.Add(str); } Debug.Log("Time2:"+Time.realtimeSinceStartup); allDatas = list.ToArray(); Debug.Log("Time3:"+Time.realtimeSinceStartup+" "+configName+" "+list.Count); break; } } } */ if (allDatas == null) { string path = PathMgr.Config_Path + configName + ".bin"; allDatas = File.ReadAllLines(path); }
今天打包出现这个错误:
03-19 14:00:07.815: I/Unity(16574): EntryPointNotFoundException: getifaddrs 03-19 14:00:07.815: I/Unity(16574): at (wrapper managed-to-native) System.Net.NetworkInformation.LinuxNetworkInterface:getifaddrs (intptr&) 03-19 14:00:07.815: I/Unity(16574): at System.Net.NetworkInformation.LinuxNetworkInterface.ImplGetAllNetworkInterfaces () [0x00000] in <filename unknown>:0 03-19 14:00:07.815: I/Unity(16574): at System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces () [0x00000] in <filename unknown>:0 03-19 14:00:07.815: I/Unity(16574): UnityEngine.GameObject:SendMessage(String, Object, SendMessageOptions) 03-19 14:00:07.815: I/Unity(16574): UICamera:Notify(GameObject, String, Object) 03-19 14:00:07.815: I/Unity(16574): UICamera:ProcessTouch(Boolean, Boolean) 03-19 14:00:07.815: I/Unity(16574): UICamera:ProcessTouches() 03-19 14:00:07.815: I/Unity(16574): UICamera:Update()
在网上搜索下:
Unfortunately this is a known bug in Mono for Android. The bug report is available here.
https://bugzilla.xamarin.com/show_bug.cgi?id=1969
是因为System.Net.NetworkInformation.GetAllNetworkInterfaces()在android上会报错导致的。
近期评论