宕機(jī)bug日志分析:
通過(guò)logcat觀察到的宕機(jī)堆棧
案例一
ParticleSystemRenderer::UpdateCachedMesh()atParticleSystemRenderer.cpp:
0x2053c8c:push{r4,r5,r6,r7,lr}
0x2053c8e:add? ? r7,sp,#0xc
0x2053c90:push.w{r8,r10,r11}
0x2053c94:subsp,#0x8
...
0x2053c9a:mov.w? r10,#0x0
...
0x2053d16:str.w? r10,[sp,#4]
...
0x2053d42:blx0x294c5d8;symbol stubfor:memcpy
0x2053d46:ldr.w? r10,[sp,#4]? ? ? ? ? ? ; The game crashes here
0x2053d4a:b0x2053db0;ParticleSystemRenderer::UpdateCachedMesh()+292[inlined]ListElement::GetNext()constatLinkedList.h:71
案例二:
09-29?22:14:48.257?3093-3093/??A/DEBUG:?????r0?be2aabb0??r1?00000000??r2?0000000c??r3?00000000
09-29?22:14:48.257?3093-3093/??A/DEBUG:?????r4?cc83fc10??r5?cc0ce8d0??r6?be2aabb0??r7?0000000c
09-29?22:14:48.257?3093-3093/??A/DEBUG:?????r8?cc83fdac??r9?00000000??sl?00000006??fp?00000000
09-29?22:14:48.257?3093-3093/??A/DEBUG:?????ip?80000000??sp?eeb72290??lr?e0d8111c??pc?f6df87cc??cpsr?a0010010
09-29?22:14:48.307?3093-3093/??A/DEBUG:?backtrace:
09-29?22:14:48.307?3093-3093/??A/DEBUG:?????#00?pc?000177cc??/system/lib/
libc.so?(__memcpy_base+272)
libunity.so?(_ZN22ParticleSystemRenderer16UpdateCachedMeshEv+684)
libunity.so?(_ZN18AwakeFromLoadQueue30PersistentManagerAwakeFromLoadEi17AwakeFromLoadMode+176)
libunity.so?(_ZN18AwakeFromLoadQueue30PersistentManagerAwakeFromLoadEv+128)
libunity.so?(_ZN18LoadSceneOperation21CompleteAwakeSequenceEv+132)
libunity.so?(_ZN18LoadSceneOperation25PlayerLoadSceneFromThreadEv+316)
libunity.so?(_ZN18LoadSceneOperation19IntegrateMainThreadEv+184)
libunity.so?(_ZN14PreloadManager26UpdatePreloadingSingleStepENS_21UpdatePreloadingFlagsEi+388)
libunity.so?(_ZN14PreloadManager16UpdatePreloadingEv+328)
libunity.so?(_Z10PlayerLoopbbP10IHookEvent+616)
?/data/app/com.funova.metaworld-2/lib/arm/
libunity.so?(_Z15UnityPlayerLoopv+880)
libunity.so?(_Z12nativeRenderP7_JNIEnvP8_jobject+264)
?2/oat/arm/base.odex?(offset?0x22000)?(boolean?com.unity3d.player.UnityPlayer.nativeRender()+76)
?2/oat/arm/base.odex?(offset?0x22000)?(boolean?com.unity3d.player.UnityPlayer.a(com.unity3d.player
從報(bào)錯(cuò)信息字面意思來(lái)看,是在渲染過(guò)程中巷波,更新緩存的網(wǎng)格信息時(shí)灾常,內(nèi)存拷貝失敗室叉,導(dǎo)致宕機(jī)护姆。
可以初步判斷是mesh這類資源的出的問(wèn)題,并且是在需要mesh進(jìn)行內(nèi)存拷貝的時(shí)候。帶著這個(gè)疑問(wèn)去搜索了官方資料。
在Models 導(dǎo)入的說(shuō)明文檔中到找到了一個(gè)選項(xiàng):Read/Write Enabled 如果設(shè)置為enabled的話韭山,那就可以進(jìn)行內(nèi)存拷貝。 文檔連接
修復(fù)該宕機(jī)bug冷溃,就是需要把 Read/Write Enabled 勾上選項(xiàng)
Read/Write Enabled 選項(xiàng)說(shuō)明
Enables the mesh to be written at runtime so you can modify the data; it makes a copy in memory. When this option is turned off, it saves memory since Unity can unload a copy of mesh data in the game. However, if you are scaling or instantiating meshes at runtime with a non-uniform scale, you may have to enable “Read/Write Enabled” in their import settings. The reason is that non-uniform scaling requires the mesh data to be kept in memory. Normally this is detected at build time, but when meshes are scaled or instantiated at runtime you need to set this manually. Otherwise they might not be rendered in game builds correctly. The same applies if you need to create MeshColliders at runtime.
如果導(dǎo)入的mesh需要做 non-uniform scale (不均勻縮放)钱磅,那就需要進(jìn)行一次拷貝操作,那么對(duì)于mesh導(dǎo)入時(shí)似枕,需要設(shè)定為可以讀寫(xiě)盖淡,否者就會(huì)出現(xiàn)宕機(jī)或渲染的對(duì)象不正確的情況。
補(bǔ)充說(shuō)明凿歼,mesh出現(xiàn)這類問(wèn)題的時(shí)候褪迟,對(duì)MeshColliders也需要做相同的設(shè)置操作。
從內(nèi)存優(yōu)化角度來(lái)說(shuō)答憔,最好不好在有多份的mesh存在味赃,那樣會(huì)浪費(fèi)內(nèi)存
說(shuō)明在導(dǎo)入時(shí) Scale Factor 參數(shù)的設(shè)置會(huì)比較重要
Unity’s physics system expects 1 meter in the game world to be 1 unit in the imported file. If you prefer to model at a different scale then you can compensate for it here. Defaults for different 3D packages are as follows .fbx, .max, .jas, .c4d = 0.01, .mb, .ma, .lxo, .dxf, .blend, .dae = 1 .3ds = 0.1
以上說(shuō)明根據(jù)導(dǎo)入mesh的文件的格式,與unity物理系統(tǒng)的之間1m與1個(gè)單位的對(duì)應(yīng)關(guān)系
盡量在導(dǎo)入時(shí)機(jī)會(huì)做好標(biāo)準(zhǔn)縮放了虐拓,那么就不需要在scale 或 instantiating 時(shí)進(jìn)行多份內(nèi)存拷貝了洁桌。?
// 檢測(cè)工具
public static void CheckFXBReadWriteEnable()
{
string artPath = "Assets/Resourcex/art";
var paths = Directory.GetFiles(artPath, "*.meta", SearchOption.AllDirectories).Where(s => s.ToLower().EndsWith("fbx.meta"));
foreach (string path in paths)
{
using (StreamReader fsRead = new StreamReader(path))
{
int isReadable = 0;
float globalScale = 1f;
while (!fsRead.EndOfStream)
{
string line = fsRead.ReadLine();
if (line.IndexOf("isReadable") != -1)
{
string[] items = line.Split(':');
if (items.Length==2)
{
isReadable = Int32.Parse(items[1]);
}
}
else if (line.IndexOf("globalScale") != -1)
{
string[] items = line.Split(':');
if (items.Length == 2)
{
globalScale = float.Parse(items[1]);
}
}
}
if (globalScale != 1 && isReadable == 0)
{
Debug.LogErrorFormat("import model [ {0} ] scale factor is [{1}] must set read/write enable",
path, globalScale);
}
}
}
}