PHP 垃圾回收高级特性
PHP 垃圾回收高级特性
1. 循环引用与内存泄漏
单纯的引用计数在遇到循环引用时会导致内存泄漏,主要原因是引用计数无法正确识别那些仅通过循环引用相互关联但实际上已经不可达的对象。
1.1 引用计数的基本原理
引用计数是一种内存管理机制,通过维护每个对象的引用计数来决定对象是否可以被销毁:
- 创建对象:引用计数初始为 1
- 新增引用:引用计数增加
- 删除引用:引用计数减少
- 销毁对象:当引用计数变为 0 时,对象被销毁,其内存被回收
2. 循环引用详解
2.1 循环引用的定义
循环引用是指两个或多个对象相互引用,形成一个闭环。例如:
$a = new UsersEntity();
$b = new UsersEntity();
$a->ref = $b; // $a 引用了 $b
$b->ref = $a; // $b 引用了 $a
在这个例子中:
- $a 的引用计数为 1(被 $b->ref 引用)
- $b 的引用计数为 1(被 $a->ref 引用)
注意:即使脚本中不再使用 $a 和 $b,它们的引用计数都不会变为 0,因为它们相互引用。
2.2 引用计数的局限性
引用计数无法判断循环引用对象是否真正被程序所需。即使这些对象在逻辑上不可达(没有外部引用指向它们),它们之间的引用关系仍然会导致引用计数始终大于 0。
3. 内存泄漏示例
3.1 基本示例
gc_enable(); // 启用垃圾回收
$a = new UsersEntity();
$b = new UsersEntity();
$a->ref = $b; // 循环引用
$b->ref = $a;unset($a);
unset($b);
重要:即使没有手动触发垃圾回收,这里也会出现内存泄漏。即使 $a 和 $b 已经被 unset,它们仍然在相互引用,引用计数器无法减少到 0。
3.2 实际应用示例
public function getStatusWithCycle()
{gc_enable(); // 启用垃圾回收$a = new UsersEntity();$b = new UsersEntity();$a->ref = $b; // 循环引用$b->ref = $a;unset($a);unset($b);$endStatus = gc_status();return ['end_status' => $endStatus];
}
返回结果示例:
{"data": {"end_status": {"runs": 0,"collected": 0,"threshold": 10001,"roots": 2433}}
}
4. 垃圾回收器的解决方案
为了弥补引用计数的局限性,PHP 引入了垃圾回收器(GC),采用了基于根集合(roots)和可达性分析的算法:
- 根集合:程序中所有可以直接访问的对象
- 标记阶段:遍历根集合,标记所有可达的对象
- 清除阶段:回收未被标记的对象,包括循环引用的对象
gc_collect_cycles(); // 手动触发垃圾回收
5. 自动垃圾回收机制
如果启用了垃圾回收机制,即使没有手动调用 gc_collect_cycles()
,理论上内存溢出的风险大大降低,但仍然可能发生,取决于以下因素:
5.1 自动垃圾回收触发条件
- PHP 的垃圾回收器在运行时会自动检测是否需要回收循环引用的内存资源
- 垃圾回收的触发基于根集合的增长(roots)和预定义的阈值(
gc_status()['threshold']
) - 如果 roots 增长未达到 threshold,垃圾回收不会触发
注意:如果代码中循环引用对象的生成速度超过垃圾回收器的触发速度,可能出现短期内的内存占用高峰甚至溢出。
5.2 脚本运行时长和负载
短生命周期脚本
- 大多数 PHP 网页脚本属于此类
- 脚本结束时会清理所有内存,包括循环引用的对象
- 通常不会内存溢出,但可能出现瞬间内存使用过高
长生命周期脚本
- 守护进程、队列处理器、WebSocket 服务等
- 可能持续运行并产生大量循环引用对象
- 如果垃圾回收未及时触发,内存使用会逐渐增加
6. 内存管理最佳实践
6.1 如何降低内存溢出风险
-
配置优化
- 确保
memory_limit
配置足够高 - 适当调整垃圾回收阈值
- 确保
-
代码优化
- 避免频繁创建循环引用对象
- 及时打破不必要的引用关系
-
主动管理
- 使用
unset()
及时打破引用关系 - 在适当位置手动触发垃圾回收
- 使用
6.2 监控和优化建议
-
内存监控
- 定期检查
gc_status()
的 roots 和 collected 值 - 引入内存监控和日志机制
- 定期检查
-
性能优化
- 优化代码结构
- 减少不必要的对象创建
- 适当调用
gc_collect_cycles()
总结
关键要点:
- 循环引用是引用计数机制的主要缺陷
- PHP 的垃圾回收器通过可达性分析解决循环引用问题
- 合理使用手动垃圾回收和内存监控可有效预防内存溢出
- 在高负载场景下需要特别注意内存管理
通过优化代码结构和适当调用 gc_collect_cycles()
,可以有效避免内存溢出问题。在实际应用中,应结合具体场景选择合适的内存管理策略。
相关文章:
PHP 垃圾回收高级特性
PHP 垃圾回收高级特性 1. 循环引用与内存泄漏 单纯的引用计数在遇到循环引用时会导致内存泄漏,主要原因是引用计数无法正确识别那些仅通过循环引用相互关联但实际上已经不可达的对象。 1.1 引用计数的基本原理 引用计数是一种内存管理机制,通过维护每…...
OpenFeign vs MQ:微服务通信如何选型?详解同步与异步的适用场景
OpenFeign vs MQ:微服务通信如何选型?详解同步与异步的适用场景 引言 在微服务架构中,服务之间的通信方式直接影响系统的性能、可靠性和可维护性。常见的通信方式有 OpenFeign(同步HTTP调用) 和 MQ(消息队…...
如何用命令行将 PDF 表格转换为 HTML 表格
本文将介绍如何使用命令行将可填写的 PDF 表单转换为 HTML 表单。只需几行代码即可完成转换。将可填写的 PDF 表单转换为 HTML 表单后,你可以在网页上显示这些表单。本指南使用 FormVu 来演示转换过程。 使用命令行将可填写 PDF 表单转换为 HTML 表单 你可以通过命…...
html5的响应式布局的方法示例详解
以下是HTML5实现响应式布局的5种核心方法及代码示例: 1. 媒体查询(核心方案) /* 默认样式(移动优先) */ .container {padding: 15px; }/* 中等屏幕(平板) */ @media (min-width: 768px) {.container {padding: 30px;max-width: 720px;} }/* 大屏幕(桌面) */ @media …...

如何用Python抓取Google Scholar
文章目录 [TOC](文章目录) 前言一、为什么要抓取Google Scholar?二、Google Scholar 抓取需要什么三、为什么代理对于稳定的抓取是必要的四、一步一步谷歌学者抓取教程4.1. 分页和循环4.2. 运行脚本 五、完整的Google Scholar抓取代码六、抓取Google Scholar的高级提…...
电脑革命家测试版:硬件检测,6MB 轻量无广告 清理垃圾 + 禁用系统更新
各位电脑小白和大神们,我跟你们说啊!有个超牛的东西叫电脑革命家测试版,这是吾爱破解论坛的开发者搞出来的免费无广告系统工具集合,主打硬件检测和系统优化,就像是鲁大师这些软件的平替。下面我给你们唠唠它的核心功能…...

Wireshark对usb设备进行抓包找不到USBPcap接口的解决方案
引言 近日工作需要针对usb设备进行抓包,但按照wireshark安装程序流程一步步走,即使勾选了安装USBPcap安装完成后开启wireshark依然不显示USBPcap接口,随设法进行解决。 最终能够正常显示USBPcap接口并能够正常使用进行抓包 解决方案&#x…...
题目 3298: 蓝桥杯2024年第十五届决赛真题-兔子集结
题目 3298: 蓝桥杯2024年第十五届决赛真题-兔子集结 时间限制: 2s 内存限制: 192MB 提交: 2499 解决: 309 题目描述 在森林幽静的一隅,有一村落居住着 n 只兔子。 某个月光皎洁的夜晚,这些兔子列成一队,准备开始一场集结跳跃活动。村落中…...
Unity开发之Webgl自动更新程序包
之前让客户端更新webgl程序是在程序里写版本号然后和服务器对比,不同就调用 window.location.reload(true);之前做的客户端都是给企业用,用户数少看不出来啥问题。后来自己开发一个小网站,用户数量还是挺多,然后就会遇到各种各样的…...
深入理解设计模式之状态模式
深入理解设计模式之:状态模式(State Pattern) 一、什么是状态模式? 状态模式(State Pattern)是一种行为型设计模式。它允许一个对象在其内部状态发生改变时,改变其行为(即表现出不…...

Socket 编程 UDP
目录 1. UDP网络编程 1.1 echo server 1.1.1 接口 1.1.1.1 创建套接字 1.1.1.2 绑定 1.1.1.3 bzero 1.1.1.4 htons(主机序列转网络序列) 1.1.1.5 inet_addr(主机序列IP转网络序列IP) 1.1.1.6 recvfrom(让服务…...

Jenkins实践(8):服务器A通过SSH调用服务器B执行Python自动化脚本
Jenkins实践(8):服务器A通过SSH调用服务器B执行Python自动化脚本 1、需求: 1、Jenkins服务器在74上,Python脚本在196服务器上 2、需要在服务器74的Jenkins上调用196上的脚本执行Python自动化测试 2、操作步骤 第一步:Linux Centos7配置SSH免密登录 Linux Centos7配置S…...
Spring AI系列之Spring AI 集成 ChromaDB 向量数据库
1. 概述 在传统数据库中,我们通常依赖精确的关键词或基本的模式匹配来实现搜索功能。虽然这种方法对于简单的应用程序已经足够,但它无法真正理解自然语言查询背后的含义和上下文。 向量存储解决了这一限制,它通过将数据以数值向量的形式存储…...

lua的注意事项2
总之,下面的返回值不是10,a,b 而且...
主流电商平台的反爬机制解析
随着数据成为商业决策的重要资源,越来越多企业和开发者希望通过技术手段获取电商平台的公开信息,用于竞品分析、价格监控、市场调研等。然而,主流电商平台如京东、淘宝(含天猫)等为了保护数据安全和用户体验࿰…...

前端八股之HTML
前端秘籍-HTML篇 1. src和href的区别 src 用于替换当前元素,href 用于在当前文档和引用资源之间确立联系。 (1)src src 是 source 的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置࿱…...
tiktoken学习
1.tiktoken是OpenAI编写的进行高效分词操作的库文件。 2.操作过程: enc tiktoken.get_encoding("gpt2") train_ids enc.encode_ordinary(train_data) val_ids enc.encode_ordinary(val_data) 以这段代码为例,get_encoding是创建了一个En…...

鲲鹏Arm+麒麟V10,国产化信创 K8s 离线部署保姆级教程
Rainbond V6 国产化部署教程,针对鲲鹏 CPU 麒麟 V10 的离线环境,手把手教你从环境准备到应用上线,所有依赖包提前打包好,步骤写成傻瓜式操作指南。别说技术团队了,照着文档一步步来,让你领导来都能独立完成…...
历年厦门大学计算机保研上机真题
2025厦门大学计算机保研上机真题 2024厦门大学计算机保研上机真题 2023厦门大学计算机保研上机真题 在线测评链接:https://pgcode.cn/school 数字变换过程的最大值与步数 题目描述 输入一个数字 n n n,如果 n n n 是偶数就将该偶数除以 2 2 2&…...

【C++ Qt】认识Qt、Qt 项目搭建流程(图文并茂、通俗易懂)
每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 绪论: 本章将开启Qt的学习,Qt是一个较为古老但仍然在GUI图形化界面设计中有着举足轻重的地位,因为它适合嵌入式和多种平台而被广泛使用…...

IoT/HCIP实验-1/物联网开发平台实验Part2(HCIP-IoT实验手册版)
文章目录 概述产品和设备实例的产品和设备产品和设备的关联单个产品有多个设备为产品创建多个设备产品模型和物模型设备影子(远程代理) 新建产品模型定义编解码插件开发编解码插件工作原理消息类型与二进制码流添加消息(数据上报消息…...

Replacing iptables with eBPF in Kubernetes with Cilium
source: https://archive.fosdem.org/2020/schedule/event/replacing_iptables_with_ebpf/attachments/slides/3622/export/events/attachments/replacing_iptables_with_ebpf/slides/3622/Cilium_FOSDEM_2020.pdf 使用Cilium,结合eBPF、Envoy、Istio和Hubble等技术…...
推荐系统排序指标:MRR、MAP和NDCG
文章目录 MRR: Mean Reciprocal RankMAP: Mean Average PrecisionNDCG: Normalized Discounted Cumulative Gain3个度量标准来自于两个度量家族。第一种度量包括基于二进制相关性的度量。这些度量标准关心的是一个物品在二进制意义上是否是好的。第二个系列包含基于应用的度量。…...

数学建模之最短路径问题
1 问题的提出 这个是我们的所要写的题目,我们要用LINGO编程进行编写这个题目,那么就是需要进行思考这个怎么进行构建这个问题的模型 首先起点,中间点,终点我们要对这个进行设计 2 三个点的设计 起点的设计 起点就是我们进去&am…...

测试概念 和 bug
一 敏捷模型 在面对在开发项目时会遇到客户变更需求以及合并新的需求带来的高成本和时间 出现的敏捷模型 敏捷宣言 个人与交互重于过程与工具 强调有效的沟通 可用的软件重于完备的文档 强调轻文档重产出 客户协作重于合同谈判 主动及时了解当下的要求 相应变化…...

zynq 级联多个ssd方案设计(ECAM BUG修改)
本文讲解采用zynq7045芯片如何实现200T容量高速存储方案设计,对于大容量高速存储卡,首先会想到采用pcie switch级联方式,因为单张ssd的容量是有限制的(目前常见的m.2接口容量为4TB,U.2接口容量为16TB)&…...

brep2seq 论文笔记
Brep2Seq: a dataset and hierarchical deep learning network for reconstruction and generation of computer-aided design models | Journal of Computational Design and Engineering | Oxford Academic 这段文本描述了一个多头自注意力机制(MultiHead Attenti…...

【运维实战】Linux 中设置 sudo ,8个有用的 sudoers 配置!
在Linux及其他类Unix操作系统中,只有 root 用户能够执行所有命令并进行关键系统操作,例如安装更新软件包、删除程序、创建用户与用户组、修改重要系统配置文件等。 但担任 root 角色的系统管理员可通过配置sudo命令,允许普通系统用户执行特定…...
Ad Hoc
什么是 Ad Hoc? Ad hoc 一词源于拉丁语,意为“为此目的”或“为此特定原因”。一般来讲,它指的是为解决某一特定问题或任务(而非为了广泛重复应用)而设计的行动、解决方案或组合。在加密货币和区块链领域,…...

江科大SPI串行外设接口hal库实现
hal库相关函数 初始化结构体 typedef struct {uint32_t Mode; /*SPI模式*/uint32_t Direction; /*SPI方向*/uint32_t DataSize; /*数据大小*/uint32_t CLKPolarity; /*时钟默认极性控制CPOL*/uint32_t CLKPhase; /*…...