25

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

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

这对方法有什么作用?如果这意味着对象可以回收相同的方法,那么如果你想节省内存,为什么不能将类的所有方法都声明为静态?

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

4

8 回答 8

19

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

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

于 2012-10-19T22:03:59.343 回答
6

查看静态与单例测试: 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

于 2012-10-19T22:18:09.410 回答
4

在 PHP 中使用静态方法和属性会占用更少的内存吗?

大概。但是,你为什么要搞乱你的 OOP 架构呢?

有关系吗?

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

于 2012-10-19T22:05:59.780 回答
2

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

更有趣的是静态和非静态方法的性能差异

于 2014-05-07T17:45:42.910 回答
1

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

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

阅读静态关键字以更好地理解这一点。

于 2012-10-19T22:06:55.243 回答
1

我刚刚改进了 Stanislav 链接的基准以使其生效:

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 作为参数传递”几乎是“修改全局函数”的 2 倍
  • 调用修改静态属性的函数非常快,几乎是调用静态方法的一半。有趣的
  • MyClass::call() 花费了 Singleton::getInstance()->call() 时间的 75%,但花费了 $mySingleton->call() 的 133%
  • MyClass::call() 的成本与 (new MyClass)->call() 一样多
  • “静态”在成本上等同于“动态非存储”。十分有趣!

开发实践结论(2020 年 1 月生效):

  • 永远不要使用 $GLOBALS,'global $myVar' 超级快(并且分配 32 位?)
  • 仅使用全局变量和函数进行编程是最快的 PHP 吗?老派摇滚!
  • 为大量方法调用存储一个实例然后删除它是最佳的。
  • 避免存储大量实例。
  • “实例化调用”和“静态调用”具有相同的成本

干杯

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

于 2020-01-10T13:23:23.420 回答
0

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

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

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

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

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

最后:如果您更容易使用静态参数而不是每次都实例化类,那么您应该使用静态方式。但是不要期望太多的内存提升。

于 2012-10-19T22:07:40.637 回答
-2

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

于 2012-10-19T23:04:58.110 回答