当前位置:编程学习 > C#/ASP.NET >>

死循环中 new 一个引用类型的对象,是不是会影响性能

while(true)
{
     User user=userManage.GetUserById(1);
     ……    //对User对象进行操作
    Thread.Sleep(10);
}



User user=null;
while(true)
{
    user=userManage.GetUserById(1);
    ……    //对User对象进行操作
    Thread.Sleep(10);
}
哪个更好,还是都是一样的,请高手指教! --------------------编程问答-------------------- 没区别 --------------------编程问答-------------------- 虽然.net有自动回收功能,不过还是建议后一个 --------------------编程问答-------------------- 不明白你的意思,貌似与性能没啥关系

如果你说的是内存占用
如果这段代码是独立的
你可以把这段代码提取到一个方法里
那么当方法执行完毕后,该对象已具备被回收条件~ --------------------编程问答-------------------- 是执行完方法才自动回收,还是执行完循环体就自动回收?这个方法是死循环,是不是永远都不会自动回收? --------------------编程问答-------------------- 哦,明白了! --------------------编程问答--------------------
引用 2 楼 bdmh 的回复:
虽然.net有自动回收功能,不过还是建议后一个


请给出建议后一个的理由吧
感觉后一个是画蛇添足 --------------------编程问答--------------------
引用 6 楼 viena 的回复:
引用 2 楼 bdmh 的回复:
虽然.net有自动回收功能,不过还是建议后一个


请给出建议后一个的理由吧
感觉后一个是画蛇添足

没有什么理由,性质是一样的,可能是个习惯吧,我还是习惯后面的写法 --------------------编程问答-------------------- 如果较真的话,后一个是有楼主说的性能问题的
前一个在循环执行完毕,所有对象都可自动回收
而后一个,循环执行完后,仍突然保持着一个User对象的引用

当然,一般情况下一个普通对象占用的内存基本是可以忽略不计的~  --------------------编程问答-------------------- 仍突然=〉仍然 --------------------编程问答-------------------- 后一个中那个User对象,只有在当前作用域(比如所在的方法)结束,才符合垃圾回收条件 --------------------编程问答--------------------
引用 8 楼 viena 的回复:
如果较真的话,后一个是有楼主说的性能问题的
前一个在循环执行完毕,所有对象都可自动回收
而后一个,循环执行完后,仍突然保持着一个User对象的引用

当然,一般情况下一个普通对象占用的内存基本是可以忽略不计的~

你的意思是执行完一次循环后,循环中的对象会自动回收吗?
我上面只是一个例子,实际上循环体中的一个对象有300-400个字节 --------------------编程问答-------------------- 不论哪个,你都new了很多次。 --------------------编程问答-------------------- 实际看了下生成的IL

Debug版后一种在最开始多了一行 ldnull,一行 stloc
Release版完全一样

结论:没有差别 --------------------编程问答-------------------- 我现在就是没弄清楚,死循环中的对象是执行完循环体就回收,还是执行完方法体才回收? --------------------编程问答-------------------- 如果你习惯用后一种写法, 我就呆以猜你是C/C++出身的,至少不是一开始学编程就用C#的 --------------------编程问答--------------------
引用 14 楼 liaoliang891230 的回复:
我现在就是没弄清楚,死循环中的对象是执行完循环体就回收,还是执行完方法体才回收?

建议你先看下.NET GC原理。回不回收最基本的是看有没有GC root,其次看是否实现Finalize方法。具体就不详细说了。你可以用WinDbg attach到进程上用dps esp来查看当前栈内存中的内容。栈上引用的managed heap中的对象都是GC root,不会被回收。 --------------------编程问答--------------------
引用 14 楼 liaoliang891230 的回复:
我现在就是没弄清楚,死循环中的对象是执行完循环体就回收,还是执行完方法体才回收?


垃圾回收用专门的线程在执行,优先级是比较低的,所以通常回收和变量的死亡不同步,前者滞后

--------------------编程问答-------------------- 关于回收时机的问题,答案是回收时机是不确定的。 --------------------编程问答-------------------- 都不是
GC觉得内存不够了才回收

引用 14 楼 liaoliang891230 的回复:
我现在就是没弄清楚,死循环中的对象是执行完循环体就回收,还是执行完方法体才回收?
--------------------编程问答--------------------
引用 14 楼 liaoliang891230 的回复:
我现在就是没弄清楚,死循环中的对象是执行完循环体就回收,还是执行完方法体才回收?

如果是执行完方法体才回收的话,我就要用 viena 兄台建议的方法,把循环体中的代码提取到另一个方法中 --------------------编程问答--------------------
引用 20 楼 liaoliang891230 的回复:
引用 14 楼 liaoliang891230 的回复:
我现在就是没弄清楚,死循环中的对象是执行完循环体就回收,还是执行完方法体才回收?

如果是执行完方法体才回收的话,我就要用 viena 兄台建议的方法,把循环体中的代码提取到另一个方法中

回收时机是不确定的,跟是否是大对象,是强引用还是弱引用,是否类实现了Finalize方法,具体怎么实现(有的Finalize方法代码写的不好会造成对象复生),gc root等等都有关系。 --------------------编程问答-------------------- 不能说是回收,应该说是释放。对象在跳出方法体都会被释放,执行完一次循环,那一次循环中的对象会不会被释放呢? --------------------编程问答-------------------- 如果你的循环中没有Sleep(),我可以负责任地告诉你,回收是在循环结束后进行的
--------------------编程问答-------------------- 如果你是说C++那种做法,那么C#里没有那回事
只要GC没有去回收,那么对象就还在内存里,只是没人(可能出了GC)能访问到

引用 22 楼 liaoliang891230 的回复:
不能说是回收,应该说是释放。对象在跳出方法体都会被释放,执行完一次循环,那一次循环中的对象会不会被释放呢?
--------------------编程问答--------------------
引用 17 楼 yangglemu 的回复:
垃圾回收用专门的线程在执行,优先级是比较低的,所以通常回收和变量的死亡不同步,前者滞后


引用 23 楼 yangglemu 的回复:
如果你的循环中没有Sleep(),我可以负责任地告诉你,回收是在循环结束后进行的


你不觉得这很矛盾吗? --------------------编程问答-------------------- 都一样吧。
只不过是局部变量范围不一样了而已。 --------------------编程问答-------------------- 对性能的影响没什么区别,唯一的不同是作用域不同而已,如果要外部可以访问,声明就得放在外面。 --------------------编程问答-------------------- --------------------编程问答--------------------
引用 22 楼 liaoliang891230 的回复:
不能说是回收,应该说是释放。对象在跳出方法体都会被释放,执行完一次循环,那一次循环中的对象会不会被释放呢?


对象在跳出方法体的时候不会释放,顶多只是被声明没有被引用,即当垃圾回收时确认可以回收资源

引用 23 楼 yangglemu 的回复:
如果你的循环中没有Sleep(),我可以负责任地告诉你,回收是在循环结束后进行的


不会回收,回收和Sleep无任何关系

大致是
1. 程序运行之初会分配一大段连续内存,除手动GC.Collect的情况,当程序运行至内存不够时,会进行垃圾回收
2. 跳出方法体只是在CLR中对象的被引用计数减一,到0为止,表示没有被引用,即在垃圾回收执行时该内存可以被回收;

垃圾回收比较复杂,还是建议去看看资料  我看的是 CLR via C# --------------------编程问答-------------------- 没有任何差别,但是本着让变量的作用域尽可能小的原则,应使用第一个,当然,这只是出于培养编码风格上的考虑。至于提到的垃圾回收,在这里完全是个伪命题,垃圾回收是针对对象来说的,而不是针对变量的。当一个引用类型的对象没有根的时候,他就成了一个可以回收的对象。

假设你没有把 user 对象存到什么列表里,也没有让他侦听什么事件。第一种写法,每次循环体执行完毕的时候, user 变量超出范围,他所引用的对象不再有根,于是,这个对象成为可回收的对象。第二种写法仅仅有一点点差别,当执行user=userManage.GetUserById(1);后,user变量指向了新的对象,他所指向的旧对象不再有根,于是旧对象变成可以回收的对象。这两种写法是一回事。
--------------------编程问答-------------------- --------------------编程问答-------------------- 我觉得区别不大。userManage.GetUserById(1);返回的类型就是引用类型(类),每次循环时会重新复写user对象。 --------------------编程问答-------------------- 没区别 --------------------编程问答-------------------- 当然 有区别,习惯 后一种。
 两种 都new一个对象,但是
前一种,每次 都 在 栈中声明了一个 变量,指向new出来的对象。
后一种,是在循环前面就声明好了变量,不会重复创建,只是指向不同的引用对象。
至于 释放问题,两种 都没有真正释放,只是 作用域问题,能不能访问。
--------------------编程问答-------------------- 后一个好......... --------------------编程问答-------------------- --------------------编程问答-------------------- 没有区别的 --------------------编程问答--------------------
引用 30 楼 phil999 的回复:
没有任何差别,但是本着让变量的作用域尽可能小的原则,应使用第一个,当然,这只是出于培养编码风格上的考虑。至于提到的垃圾回收,在这里完全是个伪命题,垃圾回收是针对对象来说的,而不是针对变量的。当一个引用类型的对象没有根的时候,他就成了一个可以回收的对象。

假设你没有把 user 对象存到什么列表里,也没有让他侦听什么事件。第一种写法,每次循环体执行完毕的时候, user 变量超出范围,他所引……

我觉得你说的对 --------------------编程问答-------------------- 没有技术区别,理论区别肯定有,正如楼上所说作用域不同 --------------------编程问答-------------------- 第一个性能好一些.引用对象会在栈上创建一个到堆上的引用,然后在堆上分配空间.第一个例子不需要去反复在栈上创建这个引用.
补充:.NET技术 ,  C#
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,