【问题标题】:Should variables be reused to optimize resource utilization?是否应该重复使用变量来优化资源利用率?
【发布时间】:2015-11-05 12:49:08
【问题描述】:

我正在使用 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);
    ...
}

第二种方式更利于代码清晰(局部变量供本地使用)。资源利用方面有区别吗?

【问题讨论】:

  • 如果您重复使用变量,可以进行多种优化。最有趣的可能是减少动态内存分配的数量。 (出于这个原因,Java 重写了部分 swing API,允许有点反范式的输入输出参数)。但是这个问题出现在许多小分配上,而不是这里可能的少数(大)分配。另外:在您的示例中,无论如何,无论哪种情况,位图都是重新分配的;您只是在重复使用参考。仅将reference 的范围更改为位图没有区别;自动变量不需要任何成本。

标签: c# memory-management global-variables


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

    并发问题 -- 如果全局变量可以被多个执行线程访问,那么同步是必要的(而且经常 忽略)。当动态链接模块与全局变量时, 即使两个独立的组合系统也可能不是线程安全的 在数十种不同环境中测试的模块是安全的。

    命名空间污染 -- 全局名称随处可见。当您认为自己使用的是全局变量时,您可能在不知不觉中最终使用了 本地(通过拼写错误或忘记声明本地)或恶 反之亦然。此外,如果您必须将具有 相同的全局变量名,如果你幸运的话,你会得到链接 错误。如果您不走运,链接器将简单地处理 与同一个对象同名。

    内存分配问题 -- 一些 环境具有内存分配方案,可以分配 全局变量很棘手。在以下语言中尤其如此 “构造函数”具有分配以外的副作用(因为,在 在这种情况下,您可以表达两个全局变量的不安全情况 相互依赖)。此外,当动态链接 模块,可能不清楚不同的库是否有自己的 全局变量的实例或全局变量是否共享。

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

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

    【讨论】:

      【解决方案3】:

      这里要理解的主要是字段和变量只是持有一个引用,内存将分配给“new”创建的对象。 所以在这两种情况下,所有创建的位图对象都需要经过垃圾回收。

      不同的是,只有在方法中引用的对象在方法执行后才准备好被收集,只有在包含该字段的对象也准备好收集时,在字段中仍然有引用的对象才准备好收集收集起来。

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

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

      【讨论】:

      • 很好的说明。或许有人可以强调,创建一个本地 reference 几乎没有任何成本。它甚至不会被隐式初始化,例如归零。只是堆栈指针会调整一点点不同。
      猜你喜欢
      • 2013-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-09
      • 2018-07-19
      • 1970-01-01
      相关资源
      最近更新 更多