在公司比较闲,让帮忙改一个奇怪的crash,没有任何log,才搞半天,发现是由于LoadLevelAsync 的Thread Loading,在乱七八糟的android机器上出现问题了,空指针,访问没有loading完的Additive场景里的东西。
下面的代码在Galaxy S4上直接crash,而且没有任何log,太恶心人了,如果项目代码一大堆,用最原始的排除法也让你累吐血
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class Boot : MonoBehaviour { class TestNULL { public void Test() { Debug.Log( "########## Test" ); } } TestNULL _test = null ; void Start () { _test.Test(); //没有NullPointer异常?! } |
整理了下,写了个Unity Plugin,准确定位空指针crash
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | void print_stack( void * ptr) { ucontext_t *ucontext = (ucontext_t*)ptr; sigcontext& sig = ucontext->uc_mcontext; gprintf( "reg[fp]: %p" , sig.arm_fp); gprintf( "reg[ip]: %p" , sig.arm_ip); gprintf( "reg[sp]: %p" , sig.arm_sp); gprintf( "reg[lr]: %p" , sig.arm_lr); gprintf( "reg[pc]: %p" , sig.arm_pc); if (hasMono) { MonoDomain* domain = mono_get_root_domain(); mono_thread_attach(domain); gprintf( "mono trace:" ); gprintf( "%s" , mono_pmip(( void *)sig.arm_pc)); MonoJitInfo* jit = mono_jit_info_table_find(domain, ( char *)sig.arm_pc); if (jit) { uint32_t code_offset = (uint32_t)((uint8_t*)sig.arm_pc - (uint8_t*)jit->code_start); MonoDebugSourceLocation* source = mono_debug_lookup_source_location (jit->method, code_offset, domain); if (source) gprintf( "\t %s:%d" , source->source_file, source->row); } } } void signal_handler( int signum, siginfo_t *info, void * ptr) { if (info->si_addr == NULL) { gprintf( "================NullPointerException Begin====================" ); gprintf( "\n" ); print_stack(ptr); gprintf( "\n" ); gprintf( "================NullPointerException End====================" ); } else { gprintf( "================UnKnownException Begin====================" ); gprintf( "\n" ); print_stack(ptr); gprintf( "\n" ); gprintf( "================UnKnownException End====================" ); } signal (signum, SIG_DFL); //kill(getpid(), signum); } |