首页 新闻 会员 周边 捐助

循环创建对象带来的性能损耗

0
悬赏园豆:30 [已解决问题] 解决于 2014-12-22 11:42

经常在网上看到在循环体创建对象带来的性能损耗(实例1),而在循环体外面却没放里面影响的大(实例2),请问怎么去证明呢?

我通过查看IL 代码,发现里面IL代码差不多。

然后又通过windbg查看创建的对象,发现对象个数是一样的。

然后在循环外调用GC.Collect();

发现循环创建的对象无论哪种方式都会被回收 

请我我到底忽略了什么?还是本来在循环体内创建对象跟在循环内的性能是一样的

实例1、

    for (int i = 0; i < 10000; i++)      

      {       

    Program       p = new Program();    

        }

 

实例2、

 

 

  Program  p=null;
            for (int i = 0; i < 10000; i++)
            {
                 p = new Program();
            }

Roc-Lee的主页 Roc-Lee | 初学一级 | 园豆:12
提问于:2014-12-19 15:43
< >
分享
最佳答案
1

如果编译器没有做优化的话,那么这两段代码的差别在变量 p 的分配和销毁次数上。

如果要考察对象的分配和销毁次数,那么你应该这样写测试代码:

//////////////////////////////////////////////////////////////////////

for (int i = 0; i < 10000; i++)      

      {       

    Program       p = new Program();    

    p.Number = i;

        }

//////////////////////////////////////////////////////////////////////

 Program  p=new Program();   

for (int i = 0; i < 10000; i++)      

      { 

    p.Number = i;

        }

 

同样的,你也要考虑编译器是否优化此段代码。

收获园豆:30
Launcher | 高人七级 |园豆:45050 | 2014-12-19 16:27

你好,我按照你的方式加了 p.Number = i;  还是感觉不出来什么区别,能请教下 加这个有什么区别吗?

 

还有请问下编译器是否优化   这个要怎么去看?谢谢

Roc-Lee | 园豆:12 (初学一级) | 2014-12-19 19:05

@S-Roc: 

你好是不是写落了?还是我没有理解你的意图

应该是 ?

Program  p=null;

for (int i = 0; i < 10000; i++)     

      {

p=new Program(); 

    p.Number = i;

        }

Roc-Lee | 园豆:12 (初学一级) | 2014-12-19 19:45

@S-Roc: 

//////////////////////////////////////////////////////////////////////

for (int i = 0; i < 10000; i++)      

      {       

    Program       p = new Program();    // 如果编译器不做优化的,会调用 10000 次 Program 的构造函数

    p.Number = i;

        }

//////////////////////////////////////////////////////////////////////

 Program  p=new Program();    // 只调用了一次 Program 的构造函数

for (int i = 0; i < 10000; i++)      

      { 

    p.Number = i;

        }

Launcher | 园豆:45050 (高人七级) | 2014-12-22 09:14

@Launcher: 

你好,这个是可以看出来的。    在我的实例1  和实例2中,我觉得是堆栈上的区别,实例1中在循环体中创建,应该存在10000个引用地址,分别指向托管中的10000个program对象,但是实例2中应该就只有1个应用地址指向最后一个创建的program对象,其他的9999个应该已经没有引用关系,等待垃圾回收。   但是研究了2天,就是找不到证据证明堆栈上有10000个引用地址 ,分别指向托管中的10000个program对象。。。。不知道,你认为我的想法有什么问题吗?

Roc-Lee | 园豆:12 (初学一级) | 2014-12-22 09:57

@S-Roc: 我先问你一个问题,在你给出的实例中,如果只考察调用 Program 构造函数的次数的话(忽略编译器优化),1 和 2 是一样的,你同意不?能理解不?

Launcher | 园豆:45050 (高人七级) | 2014-12-22 10:27

@Launcher: 同意,理解

Roc-Lee | 园豆:12 (初学一级) | 2014-12-22 10:35

@S-Roc: 

 for (int i = 0; i < 10000; i++)

    Program p;     // 创建了 10000 次 Program 类型的变量,你同意不?能理解不?

Launcher | 园豆:45050 (高人七级) | 2014-12-22 10:42

@Launcher: 同意,理解

Roc-Lee | 园豆:12 (初学一级) | 2014-12-22 10:50

@S-Roc: 那么

for (int i = 0; i < 10000; i++)

    Program p;

是不是要比 :

Program p;

for (int i = 0; i < 10000; i++)

多执行 10000 - 1 次 Program p 语句?

Launcher | 园豆:45050 (高人七级) | 2014-12-22 10:52

@Launcher: 是的

Roc-Lee | 园豆:12 (初学一级) | 2014-12-22 11:02

@S-Roc: 这就是你的实例1和实例2的差别。

Launcher | 园豆:45050 (高人七级) | 2014-12-22 11:04

@Launcher: 代码上的逻辑是这样的。  我想看看现在环境对这些代码时怎么执行的。比如你说的编译器优化。  在vs2012中 对程序集的生成配置选择 优化代码后,实例1和实例2的il代码时一样的,那应该说机器码应该也是一样的吧。   现在我想想看看不选择 优化代码,然后采取预编译的方式,看看生成的是不是一样的。  一段小小的代码 经过了  .net编译器 和jit优化,真正执行的已经不是看到的这样的,我就想看看    经过所有的优化之后,最后到底是怎么运行。   谢谢你的解答

Roc-Lee | 园豆:12 (初学一级) | 2014-12-22 11:17

@S-Roc: 我从最开始回答你的问题的时候,就一直强调一句话:“如果编译器没有做优化的话”,难道你从这句话里就推导不出“如果编译器做了优化,两段代码的机器码是一样的”吗?

“我就想看看    经过所有的优化之后,最后到底是怎么运行”—— 反编译下 IL 码,就能看出最后的执行代码是啥,有必要这里长篇累牍的提问吗?

Launcher | 园豆:45050 (高人七级) | 2014-12-22 11:32

@Launcher: 好吧 。我错了  ,吸取教训。 谢谢

Roc-Lee | 园豆:12 (初学一级) | 2014-12-22 11:41
其他回答(3)
0

我觉得这2个实例对性能的影响微乎其微吧!2种定义的方式虽有所不同,但是在for里面都实例化了。有什么差别吗?= -!没搞懂!

大楚打码人 | 园豆:4313 (老鸟四级) | 2014-12-19 16:14

据说有区别,还在研究中

支持(0) 反对(0) Roc-Lee | 园豆:12 (初学一级) | 2014-12-19 19:03
0

 你这2种方式没有区别,每次循环都会创建新的对象,

 如果是在循环外创建对象,在循环里重复给该对象赋值(不new对象),才会有很大区别

xmj112288 | 园豆:126 (初学一级) | 2014-12-19 17:34

你好,你说的是哪种写法?    你说的区别是?  能简要说下你认为的区别吗?

支持(0) 反对(0) Roc-Lee | 园豆:12 (初学一级) | 2014-12-19 19:06
0

你不需要考虑这2种写法的性能区别,你值需要了解作用域的区别就好了

吴瑞祥 | 园豆:29449 (高人七级) | 2014-12-20 11:16
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册