在我们开始之前,我先说说我很了解抽象和依赖注入的概念。我不需要在这里睁开眼睛。

好吧,我们大多数人说了很多次,却没有真正理解“不要使用全局变量”或“子句是邪恶的,因为它们是全球的”。但是,不祥的全局状态到底有什么不好呢?

我需要为应用程序进行全局配置,例如系统文件夹路径或应用程序范围的数据库凭据。

在那种情况下,除了在某种全局空间中提供这些设置之外,我看不到任何好的解决方案,这对于整个应用程序都是通用的。

我知道滥用是不好的它,但是全球空间真的那么邪恶吗?如果是的话,还有什么好的替代品?

评论

您可以使用配置类来处理对这些设置的访问。我认为最好的做法是只有一个地方可以从配置文件和/或数据库中读取配置设置,而其他对象则可以从该配置文件中获取它们。它使您的设计更加简洁和可预测。

使用全局变量有何区别?您的“一个唯一的地方”听起来很像一个Singleton。

唯一真正的邪恶是教条。

与程序员同伴一起使用全局状态就像与您的朋友使用同一把牙刷一样-您可以,但您永远不知道有人何时会决定将其推倒。
魔鬼是邪恶的。全球国家既不是邪恶也不是善良。根据您的使用方式,它可能非常有用或有害。不要听别人的话,而只是学习如何正确编程。

#1 楼

非常简短,它使程序状态不可预测。

详细来说,假设您有两个对象都使用相同的全局变量。假设您不在任何一个模块中的任何地方使用随机源,那么在执行方法之前,如果已知系统的状态,则可以预测(并因此测试)特定方法的输出。

但是,如果其中一个对象中的方法触发副作用,从而改变了共享全局状态的值,那么当您在另一个对象中执行方法时,您将不再知道起始状态是什么目的。现在,您不再能够预测执行该方法时将获得的输出,因此无法对其进行测试。

在学术层面上,这听起来可能并不那么严重,但是能够进行单元测试代码是证明其正确性(或至少适合目的)的重要一步。

在现实世界中,这可能会产生一些非常严重的后果。假设您有一个填充全局数据结构的类,另一个有使用该数据结构中的数据,更改其状态或在此过程中销毁数据的类。如果处理器类在填充器类完成之前执行了一个方法,则结果是处理器类可能有不完整的数据要处理,并且填充器类正在处理的数据结构可能会损坏或破坏。在这种情况下,程序行为将变得完全不可预测,并可能导致史诗般的损失。

此外,全局状态会损害代码的可读性。如果您的代码具有未明确引入到代码中的外部依赖关系,那么无论谁负责维护您的代码,都必须去寻找它,以找出其来源。

至于存在哪些替代方案,完全没有全局状态是不可能的,但是在实践中,通常可以将全局状态限制为包装所有其他状态的单个对象,并且决不能依赖于作用域规则您使用的语言。如果特定对象需要特定状态,则应通过将其作为参数传递给其构造函数或使用setter方法来显式地请求它。这称为依赖注入。

由于所使用的任何语言的范围规则,传递一种您已经可以访问的状态似乎很愚蠢,但是好处是巨大的。现在,如果有人孤立地查看代码,则很清楚它需要什么状态以及它来自何处。在代码模块的灵活性方面,它也具有巨大的优势,因此有在不同上下文中重用它的机会。如果传递了状态并且对状态的更改是代码块的局部状态,则可以传递您喜欢的任何状态(如果它是正确的数据类型),然后让代码处理它。用这种风格编写的代码倾向于具有松散关联的组件的集合的外观,这些组件很容易互换。模块的代码不必关心状态从何而来,而只关心如何处理它。如果将状态传递到代码块中,那么该代码块可以孤立地存在,而依赖全局状态则不是这种情况。

还有许多其他原因可以说明,通过国家来比依靠全球国家要优越得多。这个答案绝不是全面的。您可能会写一本关于全球状态为何不好的整本书。

评论


基本上,因为任何人都可以更改状态,所以您不能依赖它。

–奥德
2012年5月10日19:38

@Truth替代?依赖注入。

–rdlowrey
2012年5月10日19:42



您的主要论点实际上并不适用于有效的只读对象,例如表示配置的对象。

– Frankc
2012年5月10日21:17

这些都没有解释为什么只读全局变量不好……这是OP明确询问的。这是一个很好的答案,当OP明确提出不同观点时,OP将其标记为“接受”,这让我感到惊讶。

–康拉德·鲁道夫(Konrad Rudolph)
2012年5月11日9:18



能够对代码进行单元测试是证明其正确性(或至少适合目的)的主要步骤。不,不是。 “自从有人指出程序测试可能令人信服地证明了错误的存在,现在已经过去了二十年,但是永远无法证明它们的存在。在认真引用了这一广为人知的言论之后,软件工程师回到了今天的状态,并继续像昔日的炼金术士一样,继续完善自己的金相纯化方法,以完善自己的测试策略。” -吉克斯特拉(Djikstra),1988年。(这使它发展了4.5年……)

–梅森·惠勒
13-10-6的14:00

#2 楼

可变的全局状态是邪恶的,其原因有很多:




可变的全局状态产生的错误-许多棘手的错误是由可变性引起的。程序中任何地方的突变所引起的错误都更加棘手,因为通常很难找到确切的原因

可测试性差-如果您的全局状态可变,则需要对其进行配置用于您编写的任何测试。这使测试变得更加困难(因此人们做人的可能性就更低!)。例如对于应用程序范围的数据库凭据,如果一个测试需要访问不同于其他所有东西的特定测试数据库怎么办?

不灵活性-如果代码的一部分需要在全局状态下一个值怎么办,但另一部分需要另一个值(例如,交易期间的临时值)?您的手上突然有了一些令人讨厌的重构

函数杂质-“纯”函数(即结果仅取决于输入参数且没有副作用的函数)更容易推理并编写更大的程序。读取或操作可变全局状态的函数本质上是不纯的。

代码理解-依赖于许多可变全局变量的代码行为很难理解-您需要了解与以下对象可能的交互作用的范围全局变量,然后才能推理代码的行为。在某些情况下,此问题可能变得棘手。

并发问题-可变的全局状态在并发情况下使用时通常需要某种形式的锁定。这很难解决(是导致错误的原因),并且给代码增加了更多的复杂性(维护困难/昂贵)。

性能-多个线程在同一全局状态下不断进行猛击缓存争用,这将减慢您的系统整体速度。

可变的全局状态的替代方法:



函数参数-通常被忽略,但是更好地参数化函数通常是避免全局状态的最佳方法。它迫使您解决重要的概念性问题:此功能需要哪些信息才能完成工作?有时,具有一个称为“上下文”的数据结构是有意义的,可以将其传递给包装所有相关信息的函数链。

依赖注入-与函数参数相同,只是做了一点更早(在对象构造而不是函数调用时)。但是,如果您的依赖项是易变的对象,请当心,这会很快引起与易变的全局状态相同的问题。但是请确保它确实是一个常量,并且以后不要将其变成可变的全局状态!状态,除了可以将实例化推迟到需要它们之前。有用的例如大型的固定数据结构,需要昂贵的一次性预计算。可变的单例当然等效于可变的全局状态,因此是邪恶的:-)

动态绑定-仅在某些语言(如Common Lisp / Clojure)中可用,但这有效地使您可以将值绑定到受控对象内范围(通常基于线程本地),不会影响其他线程。在某种程度上,这是一种与全局变量相同的效果的“安全”方法,因为您知道只有当前的执行线程会受到影响。例如,在有多个线程分别处理独立事务的情况下,此功能特别有用。


评论


我认为,如果上下文是可变的,则通过函数参数或依赖项注入传递上下文对象会引起问题,这与使用可变全局状态是同样的问题。

– Alfredo Osorio
2012年5月11日16:34



所有的好东西,阿们!但是问题是关于不变的全球状态

– MarkJ
2012年5月11日19:26



@Alfredo-非常正确。虽然还不错,但至少可以对范围进行控制。但是总的来说,通过使上下文和依赖项不可变来解决问题更容易。

– mikera
2012年5月12日下午2:06

+1表示可变/不可变。不变的全局变量是可以的。即使是那些延迟加载但永不更改的。当然,不要公开全局变量,而要公开全局接口或API。

–杰西
2014年3月7日19:30



@giorgio这个问题清楚地表明,所涉及的变量在启动时会获取其值,而在程序执行期间(系统文件夹,数据库凭据)则永远不会更改。即不变,一旦赋予其值就不会改变。就个人而言,我也使用“状态”一词,因为它在一个执行过程中可能与另一个执行过程不同,或者在另一台机器上可能不同。可能会有更好的话。

– MarkJ
2014年3月22日14:47

#3 楼


由于您的整个应用程序都可以使用它,因此很难再次考虑它们
。如果您更改了与全局相关的任何内容,则所有代码都需要更改。这是一个维护上的麻烦-远远不只是简单地能够通过grep输入类型名称来找出哪些功能在使用它。
它们很糟糕,因为它们引入了隐藏的依赖关系,从而破坏了多线程,这对越来越多的应用程序来说越来越重要。一切都很难。
它们真的很难测试。
它们使调用API变得很困难。 “您必须记得在调用API之前先调用SET_MAGIC_VARIABLE()”只是乞求有人忘记调用它。它使使用API​​容易出错,从而导致难以发现的错误。通过将其用作常规参数,可以强制调用者正确提供一个值。只需将引用传递给需要它的函数即可。没那么难。

评论


好吧,您可以拥有一个封装锁定的全局配置类,并且IS旨在在任何可能的时间更改状态。我会选择这种方法,而不是从代码中的1000x位置实例化配置读取器。但是,是的,不可预测性对他们来说绝对是最糟糕的事情。

–编码器
2012年5月10日23:23

@Coder:注意,对全局变量的明智选择不是“从代码中1000x处读取配置读取器”,而是一个配置读取器,它创建了一个配置对象,该方法可以将其接受为参数(->依赖注入)。

–sleske
2012年5月10日23:52

细说:为什么grep for a type比全局更容易?问题是只读的全局变量,所以第2点和第3点无关

– MarkJ
2012年5月11日19:24

@MarkJ:我希望没有人遮住这个名字。

– DeadMG
2012年5月12日下午2:09

@ DeadMG,Re“ ..总是完全不可靠..”,对于依赖项注入也是如此。仅仅因为将其设置为参数并不意味着obj保证具有固定状态。在该函数的某个位置,您可能调用了另一个函数,该函数在顶部修改了注入变量的状态。

–起搏器
17年9月19日在18:03

#4 楼

如果您说“状态”,通常指“可变状态”。全局可变状态是完全有害的,因为这意味着程序的任何部分都可以影响其他任何部分(通过更改全局状态)。

想象一下调试未知程序:您发现函数A的行为某些输入参数的确定方法,但有时对于相同参数它的工作方式有所不同。您发现它使用了全局变量x。

,您查找了修改x的位置,并发现有五个修改它的位置。现在祝您好运,在什么情况下函数A可以执行......

评论


如此不变的全球国家不是那么邪恶吗?

– FrustratedWithFormsDesigner
2012年5月10日19:53



我要说的是,不变的全球状态是众所周知的称为“常量”的良好实践。

– Telastyn
2012年5月10日19:58

不变的全球状态不是邪恶的,它只是很糟糕:-)。它仍然存在问题,因为它引入了耦合(使更改,重用和单元测试更加困难),但是产生的问题要少得多,因此在简单情况下通常是可以接受的。

–sleske
2012年5月10日23:53

IFF确实会使用全局变量,那么只有一段代码可以对其进行修改。其余的可以免费阅读。其他人更改它的问题不会随封装和访问功能而消失。这不是这些构造的目的。

– phkahler
2012年5月11日16:35

@Pacerier:是的,无论将其用作全局变量还是局部变量,更改广泛使用的接口都是困难的。但是,这与我的观点无关,那就是使用全局变量很难理解不同代码之间的交互。

–sleske
17年9月20日在7:18

#5 楼

您回答了自己的问题。它们在“被滥用”时很难管理,但是如果知道如何包含它们,则在适当使用时可能会有用且[可]可预测。维护和对全局变量的更改通常是一场噩梦,随着应用程序大小的增加,情况变得更糟。

有经验的程序员可以说全局变量是唯一的选择,而全局变量是简单的解决方案之间的区别,因此使用它们的问题最少。但是使用它们可能会导致无尽的问题,因此建议不要使用它们。与任何不可预测的事物一样,您可以采取措施控制不可预测性,但是可以做的事情总是存在局限性。除此之外,新开发人员加入该项目的麻烦是必须处理相对未知的变量,因此反对使用全局变量的建议应该是可以理解的。

#6 楼

Singletons有很多问题-这是我脑海中最大的两个问题。


它使单元测试成为问题。全局状态可能从一次测试到下一次测试都被污染
,它强制执行“唯一的一个”硬规则,即使无法更改,该规则也会突然发生。然后需要更改使用全局可访问对象的一整套实用程序代码。这些项目既庞大又昂贵(例如,数据库连接管理器),或者包含普遍的状态信息(例如,锁定信息)。

Singleton的替代方法是在启动时创建这些Big Global Objects,并将它们作为参数传递给需要访问该对象的所有类或方法。

这里的问题是,最终您会遇到一场“包裹通过”大游戏。您有一个组件及其依赖关系图,有些类创建了其他类,每个类都必须容纳一堆依赖组件,因为它们的衍生组件(或衍生组件的组件)需要它们。

您遇到了新的维护问题。一个示例:突然,图形深处的“ WidgetFactory”组件需要一个要模拟的计时器对象。但是,“ WidgetFactory”是由“ WidgetCreationManager”的一部分“ WidgetBuilder”创建的,即使只有一个实际使用它,您也需要具有三个了解此计时器对象的类。您发现自己想要放弃并恢复为Singletons,只是使此计时器对象可全局访问。

幸运的是,这正是依赖注入框架所解决的问题。您可以简单地告诉框架它需要创建什么类,它使用反射为您找出依赖关系图,并在需要时自动构造每个对象。

因此,总而言之,单例很糟糕,替代方法是使用依赖注入框架。

我碰巧使用了温莎城堡,但您却无奈选择。请参阅2008年的本页,以获取可用框架的列表。

#7 楼

首先,要使依赖项注入是“有状态的”,您将需要使用单例,因此人们说这在某种程度上是一种错误。人们一直在使用全局上下文对象。例如,即使会话状态在本质上也是一个全局变量。不管是否通过依赖项注入传递所有信息,都不总是最好的解决方案。我目前在一个非常大的应用程序上工作,该应用程序使用许多全局上下文对象(通过IoC容器注入的单个子集),并且调试从来就不是问题。尤其是在事件驱动的体系结构中,与使用全局上下文对象而不是传递任何更改相比,它更可取。取决于您问谁。

任何东西都可以滥用,这还取决于应用程序的类型。例如,在Web应用程序中使用静态变量与在桌面应用程序中完全不同。如果可以避免使用全局变量,则可以这样做,但是有时它们有其用途。至少要确保全局数据位于清晰的上下文对象中。就调试而言,没有什么调用堆栈和某些断点无法解决。

我想强调一下,盲目使用全局变量是一个坏主意。函数应该是可重用的,并且不在乎数据来自何处-引用全局变量会将函数与特定的数据输入耦合在一起。这就是为什么应该传递它,为什么依赖项注入会有所帮助的原因,尽管您仍在使用集中式上下文存储(通过单例)。

Btw ...有些人认为依赖项注入是不好的,包括Linq的创建者,但这并不会阻止包括我自己在内的人们使用它。最终,经验将是您最好的老师。有的时候要遵守规则,有的时候要打破规则。

#8 楼

由于此处的其他一些答案区分了可变状态和不可变全局状态,因此,我想指出,即使不可变全局变量/设置也常常令人烦恼。

考虑这个问题:


...假设我需要为应用程序进行全局配置,例如系统文件夹路径或应用程序范围的数据库凭据。 ...


对,对于一个小程序来说,这可能不是问题,但是一旦在稍大的系统中使用组件执行此操作,编写自动测试就突然变得很困难。更加困难,因为所有测试(〜在同一进程中运行)必须使用相同的全局配置值。如何为多个测试(甚至可以并行)引导全局配置值。

#9 楼

好吧,对于一个,您可以遇到与单例完全相同的问题。今天看起来像“我只需要其中的一项全局”的东西,突然变成了您将来需要更多的东西。

例如,今天您创建此全局配置系统,因为您希望为整个系统进行一个全局配置。几年后,您移植到另一个系统,有人说:“嘿,您知道,如果有一个通用的全局配置和一个平台特定的配置,这可能会更好。”突然,您做了所有这些工作以使全局结构不全局,因此您可以拥有多个全局结构。目前仍在。)

考虑到使非全局性对象产生的成本通常微不足道,这样做很愚蠢。您只是在制造未来的问题。

评论


您的示例不是OP的意思。您显然是在多次实例化抽象配置(只是一个配置管理器数据结构,而没有任何特定于应用程序的首选项键),因为您希望将正在运行的程序实例中的所有键拆分为多个配置管理器类实例。 (例如,每个这样的实例可以处理一个配置文件)。

–苏So
17年11月15日在18:19

#10 楼

奇怪的是,另一个问题是由于扩展不够“全局”,它们使应用程序难以扩展。全局变量的范围是进程。

如果要通过使用多个进程或通过在多个服务器上运行来扩展应用程序,则不能。至少要等到您排除所有全局变量并将其替换为其他某种机制之后。

#11 楼


为什么全局状态如此邪恶?


可变的全局状态是邪恶的,因为我们的大脑很难一次考虑多个参数,并且很难弄清楚他们如何从时间角度和价值角度结合以影响事物。

因此,我们很难调试或测试对象,该对象的行为在程序执行过程中有多个外部原因要更改。更不用说我们必须推理将数十个这些对象放在一起的情况了。

#12 楼

在任何实际应用中,状态都是不可避免的。您可以按照自己喜欢的方式包装它,但是电子表格必须在单元格中包含数据。您可以使单元格对象仅具有用作接口的功能,但这并不限制可以在单元格上调用方法并更改数据的位置。您构建整个对象层次结构以尝试隐藏接口,以便默认情况下代码的其他部分无法更改数据。这不会阻止对包含对象的引用被任意传递。这些都不能单独消除并发问题。它确实使增加对数据的访问的难度增加了,但实际上并没有消除全局变量的感知问题。如果有人要修改状态,则将使用全局状态或通过复杂的API进行修改(后者只会阻止而不是阻止)。全局存储是为了避免名称冲突。如果加载声明相同全局名称的多个模块,则可能是行为不确定(非常难以调试,因为单元测试将通过)或链接器错误(我在想C-链接器是否对此警告或失败?)。

如果您想重用代码,则必须能够从另一个地方获取模块,并且不要让它意外地进入您的全局模块,因为它们使用了相同的名称。或者,如果您很幸运并且遇到错误,则不想更改代码的一个部分中的所有引用以防止发生冲突。

#13 楼

专为安全和健壮的系统设计而设计的语言通常会完全摆脱全局可变状态。 (可以说这意味着没有全局变量,因为不可变对象在某种意义上并不是真正有状态的,因为它们从不进行状态转换。) br />

当功能存储在全局变量中并且因此可能可读时,对谁有权访问对象的分析和最小特权原则都被颠覆了。 />通过程序的任何部分。一旦对象在全球范围内可用,就不再可能限制分析范围:
访问该对象是一项特权,不能从程序中的任何代码中保留
。 Joe-E通过验证全局范围不包含任何功能,而只包含不可变的数据,从而避免了这些问题。


所以思考它的一种方法是
/>

编程是一个分布式推理问题。大型项目的程序员需要将程序划分为可以由个人推理的部分。
范围越小,就越容易进行推理。试图证明系统属性的个人和静态分析工具,以及需要测试系统属性的测试,都是如此。
全球可用的重要授权资源使系统的属性很难被发现。原因。
因此,全局可变状态使得难以设计健壮的系统,更难以证明系统的性能,并且
更难确保测试在与生产环境类似的范围内进行测试。

全局可变状态类似于DLL hell。随着时间的流逝,大型系统的不同部分将需要与共享的可变状态部分稍有不同的行为。要解决DLL地狱和共享的可变状态不一致问题,需要在不同团队之间进行大规模协调。如果适当地确定全局状态的范围,则不会发生这些问题。

#14 楼

全球人还不错。正如在其他几个答案中所述,它们的真正问题是,今天,明天,您的全局文件夹路径可能是几个甚至数百个之一。如果您要编写一个快速的一次性程序,请使用全局变量(如果更简单)。通常,尽管如此,即使您只认为自己需要一个倍数,也可以选择。必须重组一个突然需要与两个数据库通信的大型复杂程序,这并不令人愉快。

但是它们不会损害可靠性。如果程序中的许多地方引用的数据意外更改,都可能导致问题。当枚举器在枚举中途更改时,枚举器会阻塞。事件队列事件可以彼此玩弄。线程总是会发疯。任何不是局部变量或不可更改字段的问题。全局变量是这种问题,但是您不会通过使其变为非全局变量来解决此问题。写需要同步。 (作为一千种可能出错的事情之一,例如,您抓住路径,然后将该目录删除,然后将文件夹路径更改为一个好目录,然后尝试写入已删除的目录。)是否存在问题文件夹路径是全局的,或者是程序当前正在使用的千分之一。线程。简单地说(和简单化):局部变量是好的而字段是坏的。但是以前的全局变量仍将是字段,因此,此问题(无论如何至关重要)不适用于全局字段的“好”或“邪恶”状态。 />(请注意,事件队列或递归调用可能会遇到类似的问题,但是到目前为止,多线程是最糟糕的。)请考虑以下代码:

if (filePath != null)  text = filePath.getName();
局部变量或某种常量,因为filePath为空,所以程序在运行时不会失败。支票始终有效。没有其他线程可以更改其值。否则,将无法保证。当我开始用Java编写多线程程序时,我总是在这样的行上看到NullPointerExceptions。任何其他线程都可以随时更改该值,而且它们经常这样做。正如其他几个答案所指出的那样,这给测试带来了严重的问题。上面的声明可以工作十亿次,需要经过广泛而全面的测试,然后才能投入生产。用户将无法重现该问题,除非他们确信自己看到了东西并忘记了它,否则该问题将不会再次发生。

全球肯定有这个问题,如果您可以完全消除它们或将它们替换为常量或局部变量,这是一件非常好的事情。如果您在Web服务器上运行无状态代码,则可能可以。通常,所有多线程问题都可以由数据库解决。

但是,如果程序必须记住从一个用户操作到下一个用户操作的所有内容,则任何运行线程都可以访问该字段。将全局字段切换到非全局字段将无助于可靠性。

评论


您能否弄清楚这是什么意思?:“不是局部变量或不可更改字段的任何问题都是问题。全局变量是这种问题,但您不会通过使它们成为非全局变量来解决。”

– Andres F.
2012年5月11日0:40

@AndresF .:我扩展了答案。我想我采用的是台式机方法,该页面上的大多数人都使用更多的服务器代码和数据库。在这些情况下,“全局”可能意味着不同的含义。

–RalphChapin
2012年5月11日14:37

#15 楼

当很容易看到和访问所有全局状态时,程序员总是会这样做。您所获得的内容是直言不讳的,而且很难跟踪依赖关系(int blahblah意味着数组foo在任何情况下都是有效的)。从本质上讲,它几乎不可能维护程序不变式,因为所有内容都可以独立地旋转。 someInt与otherInt之间存在关系,这很难管理,也很难证明您是否可以随时直接更改。一些系统),但这些技能会丢失。它们主要围绕编码和命名约定展开,这是有充分理由的。与依赖人类遵循总体规划并阅读源代码相比,您的编译器和链接器在检查类/模块的受保护/私有数据中的不变量方面做得更好。

评论


“但是那些技能已经丧失了”……还不完全。我最近在一家软件公司工作,该软件公司被“ Clarion”骂着,这是一种代码生成器工具,具有类似于语言的自己的基本语言,缺乏诸如将参数传递给子例程的功能。 “改变”或“现代化”,终于对我的言论感到厌烦,并把我描绘成缺乏能力和无能。我要走了

–路易斯·萨默斯(Louis Somers)
2012年5月13日18:21

#16 楼

我不会说全局变量是好是坏,但是我要添加到讨论中的事实是,如果您不使用全局状态,那么您可能会浪费大量内存,特别是当您使用类将其依赖项存储在字段中时。

对于全球国家来说,没有这样的问题,一切都是全球性的。

例如:设想以下情形:您有一个10x10的网格,该网格由类“ Board”和“ Tile”组成。

如果要以OOP方式进行操作,则可能会将“ Board”对象传递给每个“ Tile”。
现在让我们说“平铺”有2个“字节”类型的字段来存储其坐标。对于一个图块,在32位计算机上占用的总内存为(1 +1 + 4 = 6)字节:x坐标为1,y坐标为1,板子指针为4。对于10x10的图块设置,这总共提供了600个字节

现在,如果委员会位于全局范围内,则从每个图块访问的单个对象只需要为每个图块获取2个字节的内存平铺,即x和y坐标字节。这样只能提供200个字节。

因此,在这种情况下,如果仅使用全局状态,则将获得1/3的内存使用量。

除了其他方面,我想这也是为什么全局范围仍然保留在(相对)低级语言(例如C ++)中的原因

评论


这在很大程度上取决于语言。在程序可以持久运行的语言中,确实可以通过使用全局空间和单例而不是实例化许多类来节省内存,但即使是这样的论点也是不稳定的。这都是关于优先事项的。在PHP之类的语言(每个请求运行一次,并且对象不会持久)中,即使该参数也没有意义。

–马达拉的幽灵
2014年3月22日13:28

@MadaraUchiha不,这个论点绝不动摇。这是客观事实,除非某些VM或其他编译语言针对此类问题进行了一些硬性代码优化。否则它仍然是相关的。即使对于服务器端程序,过去通常是“一次性”,但在执行期间仍会保留内存。对于高负载服务器,这可能是关键点。

–luke1985
2014年3月22日13:40

#17 楼

全局状态有几个要考虑的因素:


程序存储器空间
不可变的全局变量/一次写入全局变量。
可变的全局变量
对全局变量的依赖性。

您拥有的全局变量越多,引入重复项的机会就越大,从而在重复项不同步时破坏事物。将所有全局变量保存在虚假的人类记忆中既是必要的,也是痛苦的。全局变量经常被误认为是不变的全局变量…

有效使用全局变量的函数具有额外的“隐藏”参数,使其重构起来更加困难。

全局状态不是邪恶的,但它确实要付出一定的代价–当收益超过成本时就使用它。