在 PHP 中,类变量(实例属性)和类静态变量(静态属性)的存储位置有所不同,但都不是传统意义上的"堆内存"或"栈内存"概念。

PHP 的内存管理使用自己的 Zend 内存管理器(ZMM),下面详细解释它们的存储机制:

1. 类变量(实例属性)

存储位置:对象属性存储在对象结构体中,而对象本身存储在 Zend 内存堆(ZMM 管理的堆内存)

特点:

  • 每个对象实例有自己的属性副本
  • 随对象创建而分配,对象销毁而释放
  • 存储在对象句柄指向的 zend_object 结构中

内存结构示例:

[对象变量] --> [zend_object] --> [属性哈希表]
                     |
                     v
                 [属性值存储区]

2. 类静态变量(静态属性)

存储位置:存储在 类入口(zend_class_entry) 的静态成员表中,属于 全局数据区

特点:

  • 整个类共享同一份静态变量
  • 生命周期与类相同(请求结束时或扩展卸载时释放)
  • 存储在 zend_class_entry.static_members 哈希表中

内存结构示例:

[类入口 zend_class_entry]
       |
       v
[静态成员哈希表] --> [静态变量1]
               --> [静态变量2]

3. PHP 内存管理特点

PHP 使用 Zend 内存管理器(ZMM)管理所有内存,不同于传统的 C/C++ 堆栈模型:

内存区域

存储内容

生命周期

PHP 函数调用时的临时变量

函数执行期间

Zend 内存堆

对象、数组、字符串等复杂类型

引用计数为0或请求结束时

全局数据区

类定义、静态变量、常量等

请求结束或扩展卸载时

持久化内存

跨请求的持久化资源

显式释放或进程结束时

4. 代码示例与内存分析

class Example {
    public $instanceVar = 1;          // 实例变量
    public static $staticVar = 2;    // 静态变量
}

// 创建对象时
$obj = new Example();

内存分配:

  • $obj 变量本身:栈或符号表
  • Example 对象:Zend 内存堆
  • instanceVar 存储在对象结构中
  • $staticVar:全局数据区(与类定义一起)

5. 与传统语言的对比

特性

PHP

Java/C++

对象存储

Zend 内存堆

堆内存

静态变量存储

类全局数据区

方法区/静态存储区

管理方式

引用计数 + 垃圾回收

垃圾回收/手动释放

生命周期

请求级或持久化

进程级

6. 实际内存观察

可以使用 memory_get_usage() 观察:

class MemoryTest {
    public $a = [];
    public static $b = [];
}

// 测试前
echo memory_get_usage()."\n"; // 例如: 392456

// 实例化
$obj = new MemoryTest();
$obj->a = array_fill(0, 1000, 'a');
echo memory_get_usage()."\n"; // 明显增加

// 静态变量
MemoryTest::$b = array_fill(0, 1000, 'b');
echo memory_get_usage()."\n"; // 再次增加

7. 重要结论

  1. PHP 没有传统意义的堆栈区分:所有变量都通过 Zend 内存管理器管理
  2. 实例属性:属于对象,随对象存储在 ZMM 管理的"堆"
  3. 静态属性:属于类,存储在类定义的全局数据区
  4. 性能影响:
    • 实例属性访问稍快(直接对象偏移访问)

    • 静态属性访问需要类查找(稍慢但可忽略)

  5. 内存释放:
    • 实例属性:随对象引用计数归零释放
    • 静态属性:请求结束时统一释放

在 PHP 中,开发者通常不需要关心变量具体存储在哪个物理内存区域,Zend 引擎会自动高效管理这些内存分配和释放。理解这些概念主要有助于编写更高效的代码和调试内存问题。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐