你写了一个PHP脚本,一般都不用考虑内存泄露和垃圾回收的问题,因为一般情况下你的脚本很快就执行完退出了。

但在一些运行时间长,数据量大的时候,程序运行一段时间后,php脚本就占用了过多内存,然后就报错(PHP Fatal error: Allowed memory size of 134217728 bytes exhausted)退出了。一般来说,每个页面处理结束,新建的simple_html_dom对象就应该被销毁了——但是实际上没有,很明显,内存泄露发生了。

PHP的垃圾回收机制

PHP5.3之前使用的垃圾回收机制是单纯的“引用计数”,也就是每个内存对象都分配一个计数器,当内存对象被变量引用时,计数器+1;当变量引用撤掉后,计数器-1;当计数器=0时,表明内存对象没有被使用,该内存对象则进行销毁,垃圾回收完成。

“引用计数”存在问题,就是当两个或多个对象互相引用形成环状后,内存对象的计数器则不会消减为0;这时候,这一组内存对象已经没用了,但是不能回收,从而导致内存泄露。

PHP5.3开始,使用了新的垃圾回收机制,在引用计数基础上,实现了一种复杂的算法,来检测内存对象中引用环的存在,以避免内存泄露。

查看内存是否泄露

看是否有该释放的内存没有被释放,可以简单的通过 调用  memory_get_usage  函数查看内存使用情况来判断;memory_get_usage 函数返回的内存使用数据据说不是很准确,可以使用  php 的 xdebug 扩展来获得更准确翔实的内存使用情况。

class A{
private $b;
function __construct(){
$this->b = new B($this);
}
function __destruct(){
//echo "A destruct\n";
}
} class B{
private $a;
function __construct($a){
$this->a = $a;
}
function __destruct(){
//echo "B descturct\n";
}
} for($i=0;;$i++){
$a = new A();
if($i00 == 0){
echo memory_get_usage()."\n";
}
}

上面就构造了一个会产生环状引用的例子。每次创建一个A对象的实例a,a就创建一个B对象的实例b,同时让b引用a。这样,每个A对象永远被一个B引用,而每个B对象同时被一个对象A引用,引用环就这样产生了。

在PHP5.2的环境下执行这段代码,会发现内存使用在单调上涨,也没有A和B的析构函数被执行后输出的“A/B desctruct”信息;直到内存耗尽,输出“PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 40 bytes)”。

在PHP5.3的环境下执行这段代码,则发现内存使用在上跳下窜,但是永远没有超过一个限额。程序也会输出大量的“A/B desctruct”,这说明析构函数被调用了。

我的同事的程序中,就存在这种引用的环路,而他的脚本,实在php5.2.3下执行的。simple_html_dom工具中,有两个类,分别是simple_html_dom和simple_html_dom_node,前者中有一个数组成员变量nodes,数组中每个元素都是一个simple_html_dom_node对象;而每个simple_html_dom_node对象都有一个成员变量dom,该dom的值就是前面的simple_html_dom对象——这样就形成了一个漂亮的引用环,导致了内存泄露。解决的办法也很简单,就是simple_html_dom对象在使用完毕时,主动调用其clear函数,清空其成员变量nodes,环就被打破了,内存泄露也就不会发生了。

其他

1. 垃圾回收的时机

PHP中,引用计数为0,则内存立刻释放。也就是说,不存在环状引用的变量,离开变量的作用域,内存被立刻释放。环状引用检测则是在满足一定条件下触发,所以在上面的例子中,会看到使用的内存有大幅度的波动。也可以通过 gc_collect_cycles 函数来主动进行环状引用检测。

2. &符号的影响

显式引用一个变量,会增加该内存的引用计数:

$a = "something";
$b = &$a;

此时unset($a), 但是仍有$b指向该内存区域的引用,内存不会释放。

3. unset函数的影响

unset只是断开一个变量到一块内存区域的连接,同时将该内存区域的引用计数-1;在上面的例子中,循环体内部,$a=new A(); unset($a);并不会将$a的引用计数减到零;

4. = null 操作的影响

$a = null 是直接将$a 指向的数据结构置空,同时将其引用计数归0。

5. 脚本执行结束的影响

脚本执行结束,该脚本中使用的所有内存都会被释放,不论是否有引用环。

原文地址:http://blog.snsgou.com/post-181.html

PHP的内存泄露问题与垃圾回收的更多相关文章

  1. JVM内存管理和JVM垃圾回收机制

    JVM内存管理和JVM垃圾回收机制(1) 这里向大家描述一下JVM学习笔记之JVM内存管理和JVM垃圾回收的概念,JVM内存结构由堆.栈.本地方法栈.方法区等部分组成,另外JVM分别对新生代和旧生代采 ...

  2. JVM内存管理机制和垃圾回收机制

    JVM内存管理机制和垃圾回收机制 JVM结构 图片描述: java源码编译成class文件 class文件通过类加载器加载到内存 其中方法区存放的是运行时的常量.静态变量.类信息等,被所有线程共享 堆 ...

  3. JVM的内存区域划分以及垃圾回收机制详解

    在我们写Java代码时,大部分情况下是不用关心你New的对象是否被释放掉,或者什么时候被释放掉.因为JVM中有垃圾自动回收机制.在之前的博客中我们聊过Objective-C中的MRC(手动引用计数)以 ...

  4. java内存机制和GC垃圾回收机制

    Java 内存区域和GC机制 转载来源于:https://www.cnblogs.com/zhguang/p/3257367.html 感谢 目录 Java垃圾回收概况 Java内存区域 Java对象 ...

  5. 内存缓存机制and垃圾回收机制

    一.内存缓存机制 var_dump(memory_get_usage(true)); $a="laruence"; var_dump(memory_get_usage(true)) ...

  6. 内存分析_.Net垃圾回收介绍

    垃圾回收 1.       .Net垃圾回收中涉及的名称 1.1.什么是代? 垃圾回收器为了提升性能使用了代的机制,共分为三代(Gen0.Gen1.Gen2).GC工作机制基于以下假设, 1)  对象 ...

  7. JVM·垃圾收集器与内存分配策略之垃圾回收算法!

    1.垃圾回收算法    1.1.标记-清除算法(Mark-Sweep):             过程分为“标记”和“清除”两个过程.先将所有需要回收的目标统一标记,然后再统一清除.          ...

  8. JVM内存区域划分及垃圾回收

    第一部分.闲扯+概述 近来在研读<深入理解java虚拟机>一书,读完之后做个小结,算是记录一下自己的学习所得,在成长的路上,只能死磕. 要理解JVM,就要先从其内存区域划分开始,知道其由几 ...

  9. Java JVM运行时数据区,内存管理和GC垃圾回收

    一 . 运行时数据区 程序计数器是线程私有的,是一块很小的内存空间,是当前线程执行到字节码行号的计数指示器.每个CPU处理器核心 在任何一个时刻,都只可能运行着唯一的一个线程,执行着一条指令.所以在多 ...

随机推荐

  1. CentOS 7 安装程序介绍

    (一).引导菜单 使用 UEFI 引导 Install CentOS Linux 7 选择此选项开始在你的计算机系统中使用图形安装程序安装 CentOS 7 Test this media & ...

  2. mvvm小论(暂记)

    广州-PC26(34627) 2:09:44 在android 线程最后用 handler = new Handler();            updateThread = new Runnabl ...

  3. (转)OpenStack构架知识梳理

    http://www.cnblogs.com/kevingrace/p/8459034.html-------------------Openstack架构概念图-简单汇总 原文:http://www ...

  4. h2数据库的简单使用

    1.登录H2数据库的WebConsole控制台 2.设置数据库连接 3.连接测试通过之后,点击[连接]按钮,登录到test数据库的webConsole 4.创建表 复制H2数据库提供的样例SQL脚本, ...

  5. Java 中 String 的常用方法(二)

    本文介绍剩下的一些常用的 String 中的方法. 1.replace 方法 .replaceFirst 方法和 replaceAll 方法 replace(char oldChar, char ne ...

  6. 企业如何选择最佳的SSL

    如果你的企业有意采购SSL,那么本文可以给一个很好的方向.在本文中,我们将先简要介绍SSL定义及其工作原理,并探讨目前各种可用的SSL证书类型以及企业如何选择最佳的SSL. SSL定义 SSL及传输层 ...

  7. php方法重载

    php方法重载   <?php/* * php面向对象的重写与重载重写:就是当子类继承父类的一些方法后,子类又在其内部定义了相同的方法,则这个新定义的方法会覆盖继承而来的父类的方法,子类只能调用 ...

  8. WCF中的AddressHeader作用

    客户端发送请求给服务端,服务端根据请求消息把消息转发给对应的终结点.这里面有个消息筛选机制,如果请求消息中带有地址报头相关信息,则会用地址报头匹配当前的所有终结点.所以默认情况下客户端和服务端的地址报 ...

  9. XAMPP环境的搭建

    XAMPP是一个强大的集成软件包(什么是集成软件包?就是多个软件打包一起安装了,比如office办公软件包括了word.Excel.PPT) XAMPP包括了Apache,MySQL,PHP,Perl ...

  10. RichTextBox控件

    RichTextBox控件允许用户输入和编辑文本的同时提供了比普通的TextBox控件更高级的格式特征 //color在c#中是个枚举enum 蓝色按钮:在蓝色按钮注册click事件后,richtex ...