在PHP中使用静态方法和属性是否使用较少的内存?

时间:2012-10-19 21:59:03

标签: php memory-management memory-leaks static-methods

我正在开发一个每秒可以看到几十个并发用户的Web应用程序。我有一个类将在同一页面加载中多次实例化。在该类中,我有一些属性在每个对象中始终是相同的,所以我正在考虑将这些属性声明为static,以减少在此类的多个实例时将使用的内存在同一页面请求中实例化。

这样做会为这个应用程序使用更少的内存,因为PHP只能存储一次静态属性的值吗?这样做会在并发用户之间节省内存吗,还是只在每个PHP进程中节省内存?

这对方法有何用处?如果这意味着对象可以循环使用相同的方法,那么为什么在尝试保存内存时,不会将类的所有方法声明为静态?

我不清楚为什么以及何时声明属性或方法是静态的,但我确实理解将它们声明为静态允许在不实例化类的对象的情况下访问它们(这感觉就像一个黑客......这些方法和属性应该在其他地方......不是吗?)。我特别感兴趣的是static声明影响内存使用的方式,以便在我的网络服务器上尽可能降低内存使用率......总的来说,我对发生的事情有了更好的理解

8 个答案:

答案 0 :(得分:16)

当您将类方法/变量声明为静态时,它将被绑定并由类共享,而不是对象。从内存管理的角度来看,这意味着当类定义加载到堆内存中时,会在那里创建这些静态对象。当在堆栈内存中创建类的实际对象时,并且在完成静态属性的更新时,将更新包含静态对象的堆的指针。这确实有助于减少记忆,但不是很多。

从编程范式来看,人们通常选择使用静态变量来获得架构优势而不是内存管理优化。换句话说,当你想要实现单例或工厂模式时,可能会像你提到的那样创建静态变量。它提供了更强大的方法来了解“类”级别的内容,而不是“对象”级别的内容。

答案 1 :(得分:5)

看静态与单身测试:http://moisadoru.wordpress.com/2010/03/02/static-call-versus-singleton-call-in-php/

注意:由于某些原因,stackoverflow没有显示multilne主题,所以我正在添加图片。

Number of runs  Singleton call time (s)     Static call time (s)
100             0.004005                    0.001511
1,000           0.018872                    0.014552
10,000          0.174744                    0.141820
100,000         1.643465                    1.431564
200,000         3.277334                    2.812432
300,000         5.079388                    4.419048
500,000         8.086555                    6.841494
1,000,000       16.189018                   13.696728

在此处查看更多详情:https://stackoverflow.com/a/3419411/260080

答案 2 :(得分:4)

在PHP中使用静态方法和属性是否使用更少的内存?

可能。但是,为什么你会搞乱你的OOP架构呢?

这有关系吗?

可能不是。需要记忆的是PHP本身。我坚决认为删除几个字节因为你使用静态方法不会有所作为。相反,不要加载无用的模块。例如,如果您不使用GD,请不要加载它。激活缓存以减少调用PHP的次数。

答案 3 :(得分:1)

静态方法调用在许多次迭代中更快,但静态方法并不能真正节省内存。

如果您声明的类没有任何需要对每个对象实例唯一的属性,那么您可以将每个方法和属性声明为静态。但是,如果您具有需要绑定到每个对象的属性,则静态方法没有帮助。原因是因为在静态方法中,没有对$this的引用,因此您无法从静态方法引用对象属性。

阅读Static Keyword,以便更好地了解这一点。

答案 4 :(得分:1)

一般来说,是的。静态方法和属性使用较少的内存。但是,差异非常小。

更有趣的是performance difference between static and non-static methods

答案 5 :(得分:0)

我不是PHP内存管理方面的专家,但我会说你不会节省太多。如果和节省多少取决于某些方面:

  • 对象的大小(当您创建实例时,该对象保存了多少其他数据)。
  • 您创建的对象数量。

特别是对象的数量很重要。如果您只有一个实例,则可以节省50%。在这种情况下:

案例A - 静态:您没有实例化对象,只是使用存储在内存中的类定义。但是每个REQUEST都会加载类定义,这意味着内存中的类定义与并发请求的数量相同。

案例B - 实例:除了案例A之外,每个请求还有一个此对象的实例,因此这部分软件的内存使用量增加了一倍。

最后:如果你更容易使用静态参数而不是每次实例化类,你应该采用静态方式。但是不要指望太多的记忆力提升。

答案 6 :(得分:0)

我刚刚改进了斯坦尼斯拉夫链接的基准,使其能够正常运行:

https://3v4l.org/rDpVv

Results for PHP 7.4.1:

Runs by case: 500000 
Memory usage at start: 426,320

Run                                 Duration    %       Memory
Dynamic                             0.0594      30%     496
Dynamic instantiated                0.0917      46%     0           #
Dynamic instantiated stored         0.1994      100%    48,967,472  # slowest
Storage only                        0.0422      21%     16,781,392
Cost of instations only when stored 0.1572      79%     32,186,O8O  # cost of stored instatiations minus storage cost (diff of 2 previous lines)
Static                              0.0870      44%     0           # equivalent to dynamic with instantiation
Singletons with many getInstance    0.1213      61%     376
Singletons with one getInstance     0.0669      34%     320         # equivalent to "Dynamic"
Functions assigning $GLOBALS        0.0605      30%     0           # more than 2 times longer than using "global"
Functions assigning a global        0.0458      23%     32          # fastest. 32bits allocated? probably passed by copy... odd
Functions with $counter by ref      0.0707      35%     0           # slow for functions
Functions with $counter static prop 0.0524      26%     0

备注:

  • “修改全局函数”最快,达到23%
  • “实例化,存储然后调用动态方法”最长,所以100%
  • 存储实例花费大量内存,并占总时间的21%
  • “由ref传递$ counter作为参数”几乎是“修改全局函数的”两倍。
  • 调用一个修改静态属性的函数非常快,几乎是调用静态方法的一半。好笑
  • MyClass :: call()花费Singleton :: getInstance()-> call()的时间的75%,但花费了$ mySingleton-> call()的133%
  • MyClass :: call()的费用与(新MyClass)-> call()的费用一样
  • “静态”的成本等同于“动态未存储的动态”。真的很有趣!

开发人员实践的结论(于2020年1月生效):

  • 从不使用$ GLOBALS,'global $ myVar'超级快(并分配32位?)
  • 仅使用全局变量和函数进行编程是否可能是最快的PHP?守旧派摇滚!
  • 为许多方法调用存储实例,然后删除它是最佳选择。
  • 避免存储很多实例。
  • “实例化呼叫”和“静态呼叫”的费用相同

欢呼

PS:由于结果限制,即使结果不是100%稳定,我也无法进行更多运行(在整个工作台刷新后,我看到20%的变化) PS 2:如果要禁用3v4l.org的缓存,只需在代码中的任意位置添加一个空格

答案 7 :(得分:-1)

如果您共享数据,请使用静态。它更快,并为您节省了对象实例化的过程。当你需要一个入口点时,单身人士会胜过静态。我在大约一周前在我的博客上报道了这一点。