Php引用计时器和垃圾回收机制

合集下载

php实现倒计时效果

php实现倒计时效果

php实现倒计时效果现在很多的团购⽹站上都有剩余时间的显⽰。

显⽰剩余时间可以使⽤Javascript来实现,但是我们会发现使⽤Javascript来实现的话不安全,因为Javascript获取的是客户端的时间。

⽐⽅说,这次团购已经结束了,但是懂技术的访客只要修改他客户端电脑的时间就⼜显⽰该商品还可以购买。

很明显,这不是我们⽹站设计的初衷。

团购结束了就不可以再购买啦。

这⾥写了⼀个考试系统剩余时间倒计时的显⽰代码和⼤家⼀起探讨。

实现原理:PHP获取的是服务器端的时间,我们只要设置考试的开始时间和结束时间及当前时间。

如果当前的时间不在我们的考试时间范围内,则显⽰给考⽣“当前不在考试时间段!”。

如果在考试时间范围内,则获取当前时间,结束时间减掉当前时间就是剩余的时间,将剩余时间格式化输出就是“剩余考试时间:2⼩时56分32秒”这样的形式。

服务器端获得了剩余时间后,我们还要在客户端动态的显⽰剩余时间的倒计时。

这就需要⽤AJAX来实现了。

在开始前⼤家先熟悉⼏个函数吧!PHP函数:strtotime(); //将任何英⽂⽇期转换为时间戳floor(); //舍去法取整,和int()强制转换相识json_encode() //对变量进⾏JSON编码,返回字符串简单的剩余天数计算:date_default_timezone_set('Asia/Hong_Kong');$startDate = '2015-8-11';$endDate = '2015-8-31';// 将⽇期转换为Unix时间戳$startDateStr = strtotime($startDate);$endtDateStr = strtotime($endDate);$total = $endtDateStr-$startDateStr;$now = strtotime(date('Y-m-d'));$remain = $endtDateStr-$now;echo '为期:'.$total/(3600*24).'天<br>';echo '剩余:'.$remain/(3600*24).'天';效果:简单的剩余时间计算:date_default_timezone_set('Asia/Hong_Kong');$startTime = '09:00:00';$endTime = '18:00:00';// 将时间转化为unix时间戳$startTimeStr = strtotime($startTime);$endTimeStr = strtotime($endTime);$total = $endTimeStr - $startTimeStr;$restHours = 1; // 休息1⼩时$now = strtotime(date('H:i:s'));$remain = $endTimeStr - $now;echo '上班时间:'.($total/3600-$restHours).'⼩时<br>';echo '还有:'.floor(($remain/3600)).'⼩时'.floor($remain/60).'分钟下班';效果:前后端配合实现考试剩余时间:HTML布局考试剩余时间:复制代码代码如下:<span id="hour">00</span>⼩时<span id="minute">00</span>分<span id="second">00</span>秒JS脚本function dealData(id,value){var place = document.getElementById(id);place.innerHTML = value;}window.setInterval(function(){ // 每秒从服务器取⼀次数据var ajax = new Ajax();ajax.get("remain_time.php?a="+Math.random(),function(data){eval("var dtime = "+data);dealData('hour',dtime.hour);dealData('minute',dtime.minute);dealData('second',dtime.second);});},1000);PHP代码:date_default_timezone_set('PRC');$start_time = '09:00:00';$end_time = '18:00:00';$start_famate_time = strtotime($start_time);//开始时间转化为时间戳$end_famate_time = strtotime($end_time); //结束时间转化为时间戳$now_time = time();if($end_famate_time < $now_time || $start_time > $now_time){echo '当前不在考试的时间范围内!';exit;}$remain_time = $end_famate_time-$now_time; //剩余的秒数$remain_hour = floor($remain_time/(60*60)); //剩余的⼩时$remain_minute = floor(($remain_time - $remain_hour*60*60)/60); //剩余的分钟数$remain_second = ($remain_time - $remain_hour*60*60 - $remain_minute*60); //剩余的秒数echo json_encode(array('hour'=>$remain_hour,'minute'=>$remain_minute,'second'=>$remain_second));以上就是php实现倒计时的关键代码,希望对⼤家的学习有所帮助。

引用计数类

引用计数类

引用计数类
引用计数类(Reference Counting Class)是一种用于管理对象内存分配和释放的技术。

在引用计数类中,每个对象都维护一个引用计数,用于记录有多少个其他对象正在引用该对象。

当创建一个对象时,其引用计数初始化为 1。

每当有其他对象持有对该对象的引用时,引用计数加 1。

当对象不再被任何其他对象引用时,引用计数减 1。

当引用计数为 0 时,对象将被自动删除,释放其占用的内存。

使用引用计数类的好处是可以自动释放不再使用的对象,避免内存泄漏。

它还可以提供更好的性能,因为对象的删除可以在任何时间进行,而不需要等待垃圾回收器的运行。

然而,引用计数类也有一些缺点。

例如,它可能导致循环引用的问题,即两个对象互相引用,导致它们的引用计数永远不会为 0,从而无法被正确释放。

此外,在处理复杂对象图时,管理引用计数可能会消耗额外的性能。

在实际编程中,是否使用引用计数类取决于具体的需求和场景。

对于一些简单的场景,引用计数类可能是一种简单有效的内存管理方式。

但在其他情况下,可能需要使用更复杂的垃圾回收机制来处理内存管理。

希望这个解释对你有所帮助!如果你有任何其他问题,请随时提问。

PHP编程基础与实例教程第二版练习题参考答案

PHP编程基础与实例教程第二版练习题参考答案

$var2 = 7; $var3 = 8; $max=$var1>$var2?$var1:$var2; $max=$max>$var3?$max:$var3; echo $max; ?>
第 4 章答案:
选择题: 1. D(说明:根据条件式的逻辑,要想得到 Hello, World!字符串,必须要在第一个 if 结构中 满足 else 的条件。因此$a 必须为 False,然后$b 也必须为 False。最内层的条件语句的实现 要求先前的两个变量($a 和$b)是 False,而$c 必须是 True) 2.C 3.A 4.E 编程题: <?php switch($a) { case 'a': somefunction(); break; case 'b': anotherfunction(); break; case 'c': dosomething(); break; default: donothing(); } ?>
逻辑异或(xor)运算符 0 2 程序阅读题 相等相等不相等 truetruetruetruetruefalsetruefalse aaaaaa 41 hotdogok is zero 4 问答题: 1.isset($str)用于测试变量是否设置(或者存在),empty($str)用于测试变量是否为空。 检测变量是否为空使用 is_null()和 empty()函数。 is_null()和 empty()函数的区别请参考下面的 程序: <?php $a = 0; var_dump(empty($a)); //输出:bool(true) echo "<br/>"; var_dump(is_null($a)); //输出:bool(false) ?> 2. PHP 垃圾回收机制是基于引用计数机制的垃圾回收,当一个变量的引用计数变为 0 时, PHP 将在内存中销毁这个变量,此时启动垃圾回收机制。当一个变量被初始化或者赋值给 另一个变量时引用计数会加 1,当变量或者被赋值的变量被销毁或者被侦测到无用时引用计 数会减一,当垃圾收集的进程运行时会释放掉引用计数为 0 的那些变量会被从内存中释放 (垃圾回收期间程序会被中断)。当脚本执行完成时所有资源都会被释放。 3. 按值传递:函数范围内对值的任何改变在函数外部都会被忽略 按引用传递:函数范围内对值的任何改变在函数外部也能反映出这些修改 区别:按值传递时,php 必须复制值。特别是对于大型的字符串和对象来说,这将会是一个 代价很大的操作。按引用传递则不需要复制值,对于性能提高很有好处。 传值只是把某一个变量的值传给了另一个变量,而引用则说明两者指向了同一个地方。 4. <?php if("0"==0){ echo "==";//输出“==” } if("0"===0){ echo "===";//没有任何输出 } ?> 5. <?php $var1 = 1;

php底层原理

php底层原理

PHP底层原理相关的基本原理PHP是一种通用的开源脚本语言,特别适用于Web开发。

它被广泛用于服务器端编程,也可以嵌入到HTML中执行。

PHP的底层原理是指PHP语言的运行机制和实现方式,包括解释器、编译器、内存管理等方面。

1. 解释器PHP是一种解释型语言,它不需要编译成二进制代码,而是通过解释器直接解析执行源代码。

PHP解释器负责将源代码转换为可执行的指令序列,并逐行执行这些指令。

PHP解释器的工作流程如下: - 读取源代码文件并进行词法分析,将源代码转换为一个个标记(Token)。

- 进行语法分析,将标记组合成表达式和语句,并生成抽象语法树(AST)。

- 解释器按照顺序遍历AST,并根据每个节点的类型执行相应的操作。

2. 编译器尽管PHP是一种解释型语言,但在实际运行过程中会使用到编译技术来提高性能。

PHP编译器负责将源代码转换为中间表示形式(Intermediate Representation),这样可以减少每次执行时的解析和分析过程。

PHP编译器的工作流程如下: - 词法分析器将源代码转换为标记。

- 语法分析器将标记组合成表达式和语句,并生成AST。

- 编译器将AST转换为中间表示形式(如字节码)。

- 中间表示形式被解释器执行。

通过使用编译器,PHP可以在每次执行时跳过词法分析和语法分析的过程,提高了代码的执行效率。

3. 内存管理PHP的内存管理是指对内存的分配和释放进行有效控制,以避免内存泄漏和内存溢出等问题。

PHP使用垃圾回收机制来自动管理内存。

PHP的垃圾回收机制基于引用计数。

每个变量都有一个引用计数器,当一个变量被引用时,其引用计数加1;当一个变量不再被引用时,其引用计数减1。

当引用计数为0时,该变量占据的内存会被释放。

除了引用计数外,PHP还使用了循环垃圾回收机制来处理循环引用导致的无法回收的对象。

循环垃圾回收机制通过检测对象之间的关联关系来判断是否存在循环引用,并进行相应处理。

希音php面试题(3篇)

希音php面试题(3篇)

第1篇一、PHP基础1. 请解释PHP的全称及其用途。

答:PHP的全称是PHP: Hypertext Preprocessor,它是一种开源的通用脚本语言,主要用于服务器端开发,能够嵌入HTML、JavaScript、XML中,用于创建动态网页和应用程序。

2. 请简述PHP的数据类型。

答:PHP支持以下数据类型:整型(int)、浮点型(float)、布尔型(bool)、字符串(string)、数组(array)、对象(object)、NULL、资源(resource)。

3. 请解释PHP中的变量声明方式。

答:在PHP中,变量以$符号开头,后跟变量名,例如:$name = "张三"。

4. 请解释PHP中的常量声明方式。

答:在PHP中,使用define()函数或const关键字声明常量,例如:define("PI", 3.14159) 或 const PI = 3.14159。

5. 请解释PHP中的函数定义和调用。

答:使用function关键字定义函数,例如:function sayHello() { echo "Hello, world!"; };调用函数时直接使用函数名,例如:sayHello()。

6. 请解释PHP中的数组操作。

答:PHP数组可以是索引数组或关联数组。

索引数组使用数字索引,关联数组使用字符串索引。

可以使用array()函数创建数组,例如:$arr = array("name" => "张三", "age" => 20);数组操作方法包括遍历、添加、删除、修改等。

7. 请解释PHP中的对象操作。

答:PHP使用面向对象编程(OOP)模型。

使用class关键字定义类,使用new关键字创建对象。

对象操作包括创建、访问、修改属性和方法。

8. 请解释PHP中的字符串操作。

垃圾回收机制

垃圾回收机制

垃圾回收机制垃圾回收是计算机科学中一种重要的机制,用于回收和释放程序中不再使用的内存空间,以提高系统的效率和性能。

1. 什么是垃圾回收机制?垃圾回收是一种自动化的内存管理技术,用于检测和回收程序中不再可用的内存对象。

它可以分析程序的运行时行为,识别不再被引用的对象,并将其释放以供其他程序使用。

2. 垃圾回收的优点- 减少内存泄漏:垃圾回收可以识别并回收不再使用的内存对象,从而减少内存泄漏的风险。

- 提高性能:回收不再使用的内存可以释放系统资源,提高程序的运行效率和响应速度。

- 简化编程:垃圾回收可以减少程序员手动管理内存的工作量,使编程更加简单和可靠。

3. 垃圾回收的实现方式垃圾回收机制可以通过以下几种方式来实现:- 引用计数:每个对象都维护一个引用计数器,当引用计数为零时,认为对象不再需要,可以进行回收。

- 标记-清除:通过标记所有可达对象,然后清除不可达对象来进行回收。

- 复制式垃圾回收:将内存分为两个区域,一部分为活跃对象,另一部分为闲置对象。

当活跃对象占满时,将活跃对象复制到闲置对象区域,然后清除活跃对象的内存。

- 分代式垃圾回收:根据对象的存活时间将内存分为多个代,然后对不同代进行不同的垃圾回收策略。

4. 垃圾回收的挑战垃圾回收虽然带来了许多优点,但也面临一些挑战:- 停顿时间:垃圾回收会导致程序的停顿,影响系统的实时性能。

- 资源消耗:垃圾回收需要消耗系统的资源,包括CPU和内存。

- 确定回收时机:确定内存对象是否不再使用是一个复杂的问题,需要进行准确的分析和判断。

5. 垃圾回收的最佳实践为了充分利用垃圾回收机制,以下是一些最佳实践:- 避免创建不必要的对象:尽量避免频繁创建和销毁对象,以减少垃圾的产生。

- 及时释放资源:在不再需要使用内存对象时,及时进行释放,以加快垃圾回收的速度。

- 使用合适的数据结构:选择合适的数据结构可以减少垃圾回收的复杂性和开销。

结论垃圾回收机制是一种重要的内存管理技术,可以提高系统的性能和可靠性。

php变量回收机制

php变量回收机制

php变量回收机制PHP变量回收机制在PHP中,变量的回收机制是指当一个变量不再被使用时,PHP会自动将其释放并回收内存空间,以便其他变量可以继续使用。

PHP 的变量回收机制是基于垃圾回收算法实现的,它能够自动管理内存,避免内存泄漏和内存溢出的问题。

1. 引用计数机制PHP的变量回收机制主要依靠引用计数来实现。

引用计数是指每个变量都有一个计数器,用来记录当前有多少个变量引用了它。

当一个变量被赋值给另一个变量时,其引用计数会自增1;当一个变量不再引用某个变量时,其引用计数会自减1。

只有当一个变量的引用计数为0时,PHP才会回收它所占用的内存空间。

2. 循环引用问题然而,引用计数机制并不能解决循环引用的问题。

循环引用是指两个或多个变量相互引用,形成一个闭环。

在这种情况下,由于每个变量的引用计数都不为0,导致内存无法被回收,从而造成内存泄漏。

为了解决这个问题,PHP引入了垃圾回收器。

3. 垃圾回收器PHP的垃圾回收器会定期扫描内存,检查哪些变量已经不再被使用。

当发现某个变量的引用计数为0时,垃圾回收器会立即回收它所占用的内存空间。

垃圾回收器通过遍历变量之间的引用关系图,判断哪些变量是可达的,哪些是不可达的,从而确定哪些变量可以被回收。

4. 垃圾回收算法PHP的垃圾回收算法主要有两种:标记清除算法和引用计数加标记清除算法。

- 标记清除算法:这是最基本的垃圾回收算法。

它通过标记所有可达的变量,然后清除所有未标记的变量。

这种算法的缺点是需要遍历整个变量集合,效率较低。

- 引用计数加标记清除算法:这是PHP的默认垃圾回收算法。

它综合了引用计数和标记清除两种算法的优点。

首先,使用引用计数算法来快速标记出所有不可达的变量;然后,使用标记清除算法来清除这些不可达的变量。

这种算法能够有效地回收内存,并避免循环引用的问题。

5. 手动回收变量除了自动回收变量外,PHP还提供了手动回收变量的方法。

可以使用unset()函数来销毁一个变量,从而释放其占用的内存空间。

GC垃圾回收(四个算法)

GC垃圾回收(四个算法)

GC垃圾回收(四个算法)垃圾回收(GC)是现代编程语言中的一项重要功能,它的目的是回收不再使用的内存。

随着程序复杂性的增加以及内存分配的动态性,垃圾回收成为了必不可少的组成部分。

1.引用计数:引用计数是最简单的垃圾回收算法之一、它通过记录每个对象的引用计数来确定是否回收该对象。

当一个对象被引用时,其引用计数加一;当一个对象的引用被释放时,其引用计数减一、当引用计数为零时,该对象即为垃圾。

引用计数的优点在于实时性好,对象一旦变为垃圾就会被立即回收,不会造成内存的过度占用。

然而,引用计数的缺点也很明显,即无法解决循环引用的问题。

如果存在循环引用,对象之间将永远无法达到引用计数为零的状态,导致内存泄漏。

2.标记清除:标记清除算法通过两个阶段来进行垃圾回收。

首先,从根对象出发,标记所有可达对象。

然后,在第二阶段,系统将遍历所有对象,并清除未标记的对象。

标记清除算法相较于引用计数算法,能够解决循环引用的问题。

它利用可达性分析来确定对象是否仍然被引用,从而决定是否回收。

然而,标记清除算法的不足是在执行清除操作时,会产生内存碎片。

这些碎片可能会导致大量的内存分配时间,从而影响程序的性能。

3.复制收集:复制收集算法是一种高效的垃圾回收算法。

它将内存分为两个部分:From空间和To空间。

在垃圾回收过程中,所有存活的对象将被复制到To空间中,而垃圾对象则将被回收。

复制收集算法能够高效地回收垃圾对象,并解决内存碎片问题。

然而,复制收集算法的缺点是它需要额外的内存空间来完成复制操作,并且在复制过程中,需要更新所有指向存活对象的引用。

4.标记整理:标记整理算法是标记清除算法的改进版。

它首先进行标记操作,然后在清除操作之前,将所有存活的对象向一端移动,以解决内存碎片问题。

标记整理算法在性能方面优于标记清除算法,因为它能够完全避免内存碎片。

然而,与标记清除算法一样,标记整理算法也需要执行两个阶段的操作,其中标记阶段可能会占用较长的时间。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

php引用计数器和垃圾回收机制谈到引用计数器和垃圾回收机制,必须得从php变量说起。

总所周知,php 是一种弱类型,但具体表现在哪里,程序里面又是怎么表现的呢?php里面又是怎样实现引用计数器的,程序如何区分变量引用和复制?php是如何对已用完的变量进行回收,不同的php版本的不同的垃圾回收机制又是如何实现的?1.引用计数器讲到引用计数器,不得不先说一下变量的c语言实现。

如下,几个变量的结构体和联合体:zvalue_value联合体:typedef union _zvalue_value {long lval; /* long value */double dval; /* double value */struct {char *val;int len;} str;H as hTable *ht; /* hash table value */zend_object_value obj;} zvalue_value;zval的结构:struct _zval_struct {/* Variable information */zvalue_value value;/* value */zend_uint refcount__gc;zend_uchar type; /* active type */zend_uchar is_ref__gc;};zval可以看成一个容器,zvalue_value是该容器存储变量值的联合体,refcount__gc 是引用计数,记录引用数,is_ref__gc是标志这个容器是否真正的引用,type表示这个变量的类型。

根据这个表格可以发现两个有意思的地方:首先是PHP的数组其实就是一个HashTable,这就解释了为什么PHP能够支持关联数组了;其次,Resource就是一个long值,它里面存放的通常是个指针、一个内部数组的index或者其它什么只有创建者自己才知道的东西,可以将其视作一个handle。

(1)写复制(Copy on Write)<?php$var = "laruence";$var_dup = $var;$var = 1;?>PHP在修改一个变量以前,会首先查看这个变量的refcount,如果refcount大于1,PHP就会执行一个分离的例程,对于上面的代码,当执行到第三行的时候,PHP发现$var 指向的zval的refcount大于1,那么PHP就会复制一个新的zval出来,将原zval的refcount 减1,并修改symbol_table,使得$var和$var_dup分离(Separation)。

这个机制就是所谓的copy on write(写时复制)。

题外话:写时复制技术的一个比较有名的应用是在unix类操作系统内核中,当一个进程调用fork 函数生成一个子进程的时候,父子进程拥有相同的地址空间内容,在老版本的系统中,子进程是在fork 的时候就将父进程的地址空间中的内容都拷贝一份,对于规模较大的程序这个过程可能会有着很大的开销,更崩溃的是,很多进程在fork之后,直接在子进程中调用exec执行另外一个程序,这样原来花了大量时间从父进程复制的地址空间都还没来得及碰一下就被新的进程地址空间代替,这显然是对资源的极大浪费,所以在后来的系统中,就使用了写时复制技术,fork之后,子进程的地址空间还是简单的指向父进程的地址空间,只有当子进程需要写地址空间中的内容的时候,才会单独分离一份(一般以内存页为单位)给子进程,这样就算子进程马上调用exec函数也没关系,因为根本就不需要从父进程的地址空间中拷贝内容,这样节约了内存同时又提高了速度。

(2)写改变(change on writ )开始在zval里面我们看到一个字段is_ref__gc,到底如何是怎样产生作用的呢?现在我们知道,当使用变量复制的时候,PHP内部并不是真正的复制,而是采用指向相同的结构来尽量节约开销。

那么,对于PHP中的引用,那又是如何实现呢?<?php$var = "laruence";$var_ref = &$var;$var_ref = 1;?>这段代码结束以后,$var也会被间接的修改为1,这个过程称作(change on write:写时改变)。

那么ZE是怎么知道,这次的复制是不需要Separation的呢?这个时候就要用到zval中的is_ref字段了:对于上面的代码,当第二行执行以后,$var所代表的zval的refcount变为2,并且同时置is_ref为1。

当使用引用时,php会把is_ref__gc即程序会如下判断该引用是否真实引用,P HP 先检查var_ref代表的zval的is_ref__gc字段,如果为1,则不分离,大体逻辑示意如下:<?phpif((*val)->is_ref || (*val)->refcount<2){//不执行Separation... ; //process}?>(3)两种方式到底怎样使用,啥时候使用?<?php$var = "laruence";$var_dup = $var;$var_ref = &$var;?>对于上面的代码,存在一对copy on write的变量$var和$var_dup, 又有一对change on write机制的变量对$var和$var_ref,这个情况又是如何运作的呢?当第二行执行的时候,和前面讲过的一样,$var_dup 和$var 指向相同的zval,refcount为2。

当执行第三行的时候,PHP发现要操作的zval的refcount大于1,则,PHP会执行Separation, 将$var_dup分离出去,并将$var和$var_ref做change on write关联。

也就是,refcount=2, is_ref=1。

(4)数值巨大变量处理当然如果我们在php中进行参数传递的时候,是否有必要对传递内容巨大的数组心存警惕,担心内存的大量流失?<?phpfunction countChina($persons){$count=0;foreach($persons as $person){if($person['nation'] == 'china')$count++;}return $count;}?>例如上面这段统计一群人中有多少个中国国籍的时候,如果有一个10W的人的数组要传进去,你是否会担心被复制后传到函数里,导致内存占用瞬间翻倍?也许你会在参数那里加一个&表示引用?php的设计者在这里有一个很巧妙的设计,引入了一个copy on write的概念,在上面的函数中,如果你不去修改$perons对象的内容,并不会有复制行为发生,内存也不会double.但是如果我想在函数里面修改数据,便于函数后面的处理,这个时候内存会double吗?如下:<?phpfunction countChina($persons){$count=0;foreach($persons as $person){if($person['nation'] == 'china'){$person['score'] = 10;$count++;}}//利用score做一些处理...return $count;}在上面的代码中,我修改了数组的成员内容,如果你不在参数里加&的话,内存消耗会逐步增加,在返回以前,内存的占用会double,为撒呢?因为为了满足你的write需要,php进行了copy,这个copy不是一次完成的,在改变第一个$persons成员的时候,会将$persons数组和其成员的地址复制过来,并不会把所有成员内容都复制过来,随着$persons成员的一个个被write,一个个也都被copy过来,内存占用线性增加,到循环结束时,double了!如果确实要修改内容,又想避免内存消耗,又不怕影响参数变量在其他地方的使用,那就在参数里加&吧。

要释放被占用的内存变量,用unset($persons)或者$persons=null都可以迅速地释放掉,你可以使用memory_get_usage进行监控,貌似这个机制比.net体系的垃圾回收机制要清晰,简单和高效,经常出现的out of memory无疑是.net庞大体系和低效内存回收机制的必然结果。

(5)unset的作用unset()并非一个函数,而是一种语言结构,这个可以通过查看编译生成的opcode看到区别,unset对应的不是一个函数调用的opcode。

那么unset到底做了什么?在unset 对应的opcode的handler中可以看到相关内容,主要的操作时从当前符号表中删除参数中的符号,比如在全局代码中执行unset($a),那么将会在全局符号表中删除a这个符号。

全局符号表是一张哈希表,建立这张表的时候会提供一个表中的项的析构函数,当我们从符号表中删除a的时候,会对符号a指向的项(这里是zval的指针)调用这个析构函数,这个析构函数的主要功能是将a对应的zval的refcount减1,如果refcount变成了0,那么释放这个zval。

所以当我们调用unset的时候,不一定能释放变量所占的内存空间,只有当这个变量对应的zval没有别的变量指向它的时候,才会释放掉zval,否则只是对refcount进行减1操作。

2.垃圾回收机制(1)PHP5.2中的垃圾回收算法——Reference CountingPHP5.2中使用的内存回收算法是大名鼎鼎的Reference Counting,这个算法中文翻译叫做“引用计数”,其思想非常直观和简洁:为每个内存对象分配一个计数器,当一个内存对象建立时计数器初始化为1(因此此时总是有一个变量引用此对象),以后每有一个新变量引用此内存对象,则计数器加1,而每当减少一个引用此内存对象的变量则计数器减1,当垃圾回收机制运作的时候,将所有计数器为0的内存对象销毁并回收其占用的内存。

而PHP中内存对象就是zval,而计数器就是refcount__gc。

Reference Counting简单直观,实现方便,但却存在一个致命的缺陷,就是容易造成内存泄露。

很多朋友可能已经意识到了,如果存在循环引用,那么Reference Counting 就可能导致内存泄露。

例如下面的代码:1.<?php2.3.$a = array();4.$a[] = & $a;5.unset($a);6.7.?>这段代码首先建立了数组a,然后让a的第一个元素按引用指向a,这时a的zval的refcount就变为2,然后我们销毁变量a,此时a最初指向的zval的refcount为1,但是我们再也没有办法对其进行操作,因为其形成了一个循环自引用,如下图所示:(2)PHP5.3中的垃圾回收算法——Concurrent Cycle Collection in Reference Counted Systems首先PHP会分配一个固定大小的“根缓冲区”,这个缓冲区用于存放固定数量的zval,这个数量默认是10,000,如果需要修改则需要修改源代码Zend/zend_gc.c中的常量GC_ROOT_BUFFER_MAX_ENTRIES然后重新编译。

相关文档
最新文档