经常在网上看到在循环体创建对象带来的性能损耗(实例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();
}
如果编译器没有做优化的话,那么这两段代码的差别在变量 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;
}
同样的,你也要考虑编译器是否优化此段代码。
你好,我按照你的方式加了 p.Number = i; 还是感觉不出来什么区别,能请教下 加这个有什么区别吗?
还有请问下编译器是否优化 这个要怎么去看?谢谢
@S-Roc:
你好是不是写落了?还是我没有理解你的意图
应该是 ?
Program p=null;
for (int i = 0; i < 10000; i++)
{
p=new Program();
p.Number = i;
}
@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:
你好,这个是可以看出来的。 在我的实例1 和实例2中,我觉得是堆栈上的区别,实例1中在循环体中创建,应该存在10000个引用地址,分别指向托管中的10000个program对象,但是实例2中应该就只有1个应用地址指向最后一个创建的program对象,其他的9999个应该已经没有引用关系,等待垃圾回收。 但是研究了2天,就是找不到证据证明堆栈上有10000个引用地址 ,分别指向托管中的10000个program对象。。。。不知道,你认为我的想法有什么问题吗?
@S-Roc: 我先问你一个问题,在你给出的实例中,如果只考察调用 Program 构造函数的次数的话(忽略编译器优化),1 和 2 是一样的,你同意不?能理解不?
@Launcher: 同意,理解
@S-Roc:
for (int i = 0; i < 10000; i++)
Program p; // 创建了 10000 次 Program 类型的变量,你同意不?能理解不?
@Launcher: 同意,理解
@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: 是的
@S-Roc: 这就是你的实例1和实例2的差别。
@Launcher: 代码上的逻辑是这样的。 我想看看现在环境对这些代码时怎么执行的。比如你说的编译器优化。 在vs2012中 对程序集的生成配置选择 优化代码后,实例1和实例2的il代码时一样的,那应该说机器码应该也是一样的吧。 现在我想想看看不选择 优化代码,然后采取预编译的方式,看看生成的是不是一样的。 一段小小的代码 经过了 .net编译器 和jit优化,真正执行的已经不是看到的这样的,我就想看看 经过所有的优化之后,最后到底是怎么运行。 谢谢你的解答
@S-Roc: 我从最开始回答你的问题的时候,就一直强调一句话:“如果编译器没有做优化的话”,难道你从这句话里就推导不出“如果编译器做了优化,两段代码的机器码是一样的”吗?
“我就想看看 经过所有的优化之后,最后到底是怎么运行”—— 反编译下 IL 码,就能看出最后的执行代码是啥,有必要这里长篇累牍的提问吗?
@Launcher: 好吧 。我错了 ,吸取教训。 谢谢
我觉得这2个实例对性能的影响微乎其微吧!2种定义的方式虽有所不同,但是在for里面都实例化了。有什么差别吗?= -!没搞懂!
据说有区别,还在研究中
你这2种方式没有区别,每次循环都会创建新的对象,
如果是在循环外创建对象,在循环里重复给该对象赋值(不new对象),才会有很大区别
你好,你说的是哪种写法? 你说的区别是? 能简要说下你认为的区别吗?
你不需要考虑这2种写法的性能区别,你值需要了解作用域的区别就好了