说明:自己以后遇到的null问题都贴在这里。
原文链接:http://blog.csdn.net/a237653639/article/details/50676655
using System;
namespace ConsoleApplication1 {
class Program {
static void Main( string[] args ) {
//测试一个引用设为null后,它所包含的字段是否也为null
Person person3 = new Person();
Children children1 = person3.MyChildren;
person3 = null;
Console.WriteLine( children1 == null );//false
Console.ReadKey();
}
}
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public Children MyChildren { get; set; }
public Person() {
MyChildren = new Children();
}
}
public class Children {
public int BoyNum { get; set; }
public int GirlNum { get; set; }
}
}
以上代码中的chidren1并不为null。我们可以从堆栈和托管堆思考,person3置为了null,说明new Person()在托管堆中将被GC(其中所有的堆栈变量),但是之前person3的MyChildren所指向的对象还被引用着的,而GC的必要条件是回收没有任何指向该对象的内存,所以就不会GC MyChildren所指向的对象,自然children1就不为null了。也说明person3中的MyChildren也只是4个字节的引用而已,Children对象的创建(new Children())还是在托管堆上。所以Unity中的Destroy并不意味着将这个GameObject或者Component就真的彻彻底底地销毁了,只要你的代码中还引用着其中的某个对象,那么被引用的对象就还在托管堆上,一直存在着。所以要避免再次进入场景时还引用着之前创建的对象。
有两种方案来解决,
1.在OnDestroy或OnDisable等函数中置某些引用为null,以释放无用的对象和为下次OnEnable作准备,但是该类(脚本)本身并不会被释放。
2.保证你Destroy某GameObject的同时结束所有引用到 该GameObject及其所new出来的对象 的脚本的生命周期。而结束一个脚本的生命周期只有移除该脚本或者Destroy该脚本所依附的GameObject。如果只设该脚本的enable为false,该脚本的成员的引用不会变,不会变为null,所以设enable为false是不行的。
那么为什么必须要移除该脚本或Destroy该脚本所依附的GameObject才能彻底销毁呢?
1.这两种销毁方法使毫无疑问的,那么我们从“未能彻底销毁”这个角度来谈。 从.net 的角度出发,脚本还是一个类,它继承自MonoBehavior,由Unity替我们new这个对象(类),那么只要所依附的GameObject一直存在,这个GameObject上的脚本组件就一直被这个GameObject引用着,不会被释放,而所谓的enable也只是用于控制继承自MonoBehavior的函数的回调,就类这个角度而言,这个类的成员还一直保存着的。这也是为什么我们设置enable为false但是还是可以引用这个脚本及其成员的原因了。