PHP - 类变量与类静态变量的内存存储位置
·
在 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. 重要结论
- PHP 没有传统意义的堆栈区分:所有变量都通过 Zend 内存管理器管理
- 实例属性:属于对象,随对象存储在 ZMM 管理的"堆"
- 静态属性:属于类,存储在类定义的全局数据区
- 性能影响:
-
实例属性访问稍快(直接对象偏移访问)
-
静态属性访问需要类查找(稍慢但可忽略)
-
- 内存释放:
- 实例属性:随对象引用计数归零释放
- 静态属性:请求结束时统一释放
在 PHP 中,开发者通常不需要关心变量具体存储在哪个物理内存区域,Zend 引擎会自动高效管理这些内存分配和释放。理解这些概念主要有助于编写更高效的代码和调试内存问题。
更多推荐



所有评论(0)