是否应重用变量以优化资源利用率?

时间:2015-11-05 12:49:08

标签: c# memory-management global-variables

我正在使用Microsoft Visual C#2010。我有几种方法使用大位图进行本地处理,每种方法都可以多次调用。
我可以声明一个全局变量并重用它:

Bitmap workPic, editPic;
...
void Method1() {
    workPic = new Bitmap(editPic);
    ...
}
void Method2() {
    workPic = new Bitmap(editPic.Width * 2, editPic.Height * 2);
    ...
}

或在每个方法中声明一个局部变量:

Bitmap editPic;
...
void Method1() {
    Bitmap workPic = new Bitmap(editPic);
    ...
}
void Method2() {
    Bitmap workPic = new Bitmap(editPic.Width * 2, editPic.Height * 2);
    ...
}

第二种方法更适合代码清晰度(局部使用的局部变量)。在资源利用方面有区别吗?

3 个答案:

答案 0 :(得分:3)

如果您打算保留分配给您的内存,可以在方法后再次使用workPic,您应该将其注册为类变量。如果没有,你可以通过让它超出范围来释放记忆(总是一个好主意)。

分配一个变量对管理内存的框架并不重要。只有在紧密循环中重新创建变量时,才可以通过重用变量获益。如果您有基本类型,则甚至可以重用相同的内存。否则,只保留对分配的内存的引用,因此没有那么多的好处。

请注意DisposeworkPic非常重要,因为现在Bitmap后面的非托管内存中存在内存泄漏。最好使用using

答案 1 :(得分:3)

  

为什么在不必要时应避免使用全局变量

     

非本地化 - 当各个元素的范围有限时,源代码最容易理解。全局变量可以   由程序的任何部分读取或修改,使其变得困难   记住或推断每一种可能的用途。

     

无访问控制或约束检查 - 程序的任何部分都可以获取或设置全局变量,以及有关其的任何规则   使用很容易被打破或遗忘。 (换句话说,获取/设置   访问器通常优于直接数据访问,这是   对于全球数据来说更是如此。)通过扩展,缺乏访问权限   控制极大地阻碍了在你可能的情况下实现安全   希望运行不受信任的代码(例如使用第三方插件)。

     

隐式耦合 - 具有许多全局变量的程序通常在这些变量和耦合之间存在紧密耦合   变量和函数之间。将耦合项目分组为凝聚力   单位通常会带来更好的计划。

     

并发问题 - 如果多个执行线程可以访问全局变量,则需要同步(并且经常   忽略)。当用globals动态链接模块时,   即使两个独立的组合系统也可能不是线程安全的   在几十种不同背景下测试的模块是安全的。

     

命名空间污染 - 全球各地名称随处可见。当你认为你正在使用时,你可能会在不知不觉中最终使用全局   本地(通过拼写错误或忘记宣布当地)或恶习   反之亦然。此外,如果您必须将具有该模块的模块链接在一起   相同的全局变量名称,如果幸运的话,您将获得链接   错误。如果你运气不好,链接器将简单地处理所有用途   与同一对象同名。

     

内存分配问题 - 有些   环境有内存分配方案,分配   全局变得棘手。在语言中尤其如此   “构造函数”除了分配之外还有副作用(因为,in   那种情况下,你可以表达两个全局变量的不安全情况   相互依赖)。此外,动态链接时   模块,不清楚不同的图书馆是否有自己的模块   全局变量的实例或全局变量是否共享。

     

测试和限制 - 使用全局变量的源更难以测试,因为人们不能轻易设置'干净'   运行之间的环境。更一般地说,利用全球的来源   任何形式的服务(例如读写文件或数据库)   未明确提供给该来源的内容很难测试   出于同样的原因。对于通信系统,测试能力   系统不变量可能需要运行系统的多个“副本”   同时,任何使用共享都会受到很大阻碍   服务 - 包括全局内存 - 不提供共享   作为测试的一部分。

参考:http://c2.com/cgi/wiki?GlobalVariablesAreBad

答案 2 :(得分:1)

这里要理解的主要是字段和变量只保存一个引用,内存将被分配给由“new”创建的对象。 因此,在这两种情况下,所有创建的位图对象都需要进行垃圾收集。

不同之处在于,只有方法中引用的对象才能在方法执行后立即收集,只有当包含该字段的对象也准备好时,才能准备好收集仍然在字段中引用的对象。收集。

引入该字段有意义的唯一情况是在宿主对象的生命周期中重复使用相同的对象。

如果在方法开头重新创建对象,建议使用绝对变量。