日期:2014-05-18  浏览次数:20559 次

2种创建对象的方法,他们的性能区别很大吗?
如下代码:
方法A、方法B.
2种创建对象的方法,他们的性能区别很大吗?
方法A 是比较靠谱的吧?
C# code

        /// <summary>
        /// 查询所有菜品 【方法A】
        /// </summary>
        /// <returns>返回[IList]</returns>
        public static IList<FoodInfo> GetAllFood()
        {
            IList<FoodInfo> listFood = new List<FoodInfo>(); ;
            FoodInfo food= null;//1.创建
            string sql = "select FID,F_Pic,F_Desc from FoodInfo order by F_SendTime desc,FID desc";
            OleDbDataReader dr=SqlHelper.GetReader(sql)
            
                while (dr.Read())
                {
                    food= new FoodInfo();//2.实例化
                    food.FID = Convert.ToInt32(dr[0]);
                    food.F_Pic = dr[1].ToString();
                    food.F_Desc = dr[2].ToString();
                    listFood.Add(food);
                }
            
            return listCus;
        }


对比下面的
C# code

        /// <summary>
        /// 查询所有菜品 【方法B】
        /// </summary>
        /// <returns>返回[IList]</returns>
        public static IList<FoodInfo> GetAllFood()
        {
            IList<FoodInfo> listFood = new List<FoodInfo>(); ;
            
            string sql = "select FID,F_Pic,F_Desc from FoodInfo order by F_SendTime desc,FID desc";
            OleDbDataReader dr=SqlHelper.GetReader(sql)
            
                while (dr.Read())
                {
                    FoodInfo food == new FoodInfo();//1.创建,并且实例化
                    food.FID = Convert.ToInt32(dr[0]);
                    food.F_Pic = dr[1].ToString();
                    food.F_Desc = dr[2].ToString();
                    listFood.Add(food);
                }
            
            return listCus;
        }



------解决方案--------------------
性能完全一样的,但后一种写法可读性较好,我喜欢后一种写法。
------解决方案--------------------
while (dr.Read())
创建方法都在这里面
每次都会实例化个对象的
------解决方案--------------------
ls说的对啊。

在JAVA里面这样可能会造成内存占用增高,效率不高的情况,但是C#已经在编译期对这部分代码进行了优化。


其实从Java转行的我,还是青睐第一种的,原因是:习惯的适应性。
------解决方案--------------------
C# code

堆栈的内存分配机制

对于值类型,一般创建在线程堆栈上。但是值类型作为实例成员的一部分或发生装箱时,值类型
是存储在托管堆上的。
对于分配在堆栈上的局部变量来说,操作系统维护一个堆栈指针来指向下一个自由空间的地址,
并且堆栈的内存地址是由高位到低位向下填充。



托管堆的内存分配机制:

引用类型的实例分配于托管堆上,而线程栈是对象生命周期开始的地方。32位处理器来说,应用
程序完成进程初始化后,CLR将在进程的可用地址空间上分配一块保留的地址空间,它是进程(
每个进程可使用4GB)中可用地址空间上的一块内存区域,但并不对应于任何物理内存,这块地址
空间即是托管堆。

托管堆可划分不同区域:重要的包括垃圾回收堆(GC Heap)和加载堆(Loader Heap),GC Heap
用于存储对象实例,受GC管理;Loader Heap最重要的信息就是和元数据相关的信息,也就是Type
对象,每个Type在Loader Heap上体现为一个方法表(Method Table,创建于编译时期,主要包含类
型的特征信息、实现的接口数目等),Loader Heap不受GC控制,其生命周期是从创建到AppDomain卸载


FoodInfo food= null;//声明了一个引用类型的变量food,这不是创建!!!
它仅是一个引用(或指针),保村在线程的堆栈上,占4Byte的内存,用于保存FoodInfo对象的有
效地址,执行过程是线程栈上的分配过程。此时food为指向任何有效实例,手动初始化为null,试
图对food的任何操作将抛出NullReferenceException的异常;

while
{
接着 food= new FoodInfo();通过new操作执行对象创建,该操作对应IL中的newobj指令,执行过程
如下:
  (a) CLR按照继承关系进行递归搜素,找到System.Object类型,并返回字节总数total(根据你的成员及附加成员的总字节数计算)。
  (b) CLR在当前AppDomain对应的托管堆上搜素,找到一个连续未使用的total字节的连续空间
      并为其分配地址。注:堆得分配是向高地址扩展,和栈分配时相反的
  (c) 如果分配空间时发现内存不足,GC将启动垃圾收集操作来回收垃圾对象所占的内存。

  (d)调用构造器,进行初始化操作,完成创建。

   (e) 引用指向分配的托管堆地址
}
这个过程重复利用了一个指针,每次循环的时候都是改变这个指针指向的位置而已

while (dr.Read())
{
                    FoodInfo food == new FoodInfo();
 这个过程先执都会在线程栈上创建一个新的引用,然后(a)(b)(c)(d),然后将新的引用指向分配的托管堆空间
}



同时,二者的声明的范围不一样