文档章节

在某些情况下,为什么unset只能销毁变量,却无法清除内存中的值以及真正释放内存

 恒心
发布于 2012/10/27 19:10
字数 820
阅读 431
收藏 0
在PHP中,unset函数是用来清除变量,但在某些情况unset的行为会因为要销毁的变量的类型而有所不同。 
我们都知道PHP是动态的弱类型语言,而且PHP的写机制会使用内存处理的引用计数的复本,PHP中变量主要
有符号表中的条目和实际的变量容器,变量容器如下定义:其中refcount__gc和is_ref__gc分别表示此变
量容器的引用次数和是否被引用。
typedef struct _zval_struct zval;
typedef union _zvalue_value {    long lval;                 /* long value */
double dval;               /* double value */
    struct {                   /* string type */
        char *val;
        int len;
    } str;
    HashTable *ht;             /* hash table value */
    zend_object_value obj;
} zvalue_value;
 
struct _zval_struct {
    /* Variable information */
    zvalue_value value;        /* value */
    zend_uint refcount__gc;
    zend_uchar type;           /* active type */
    zend_uchar is_ref__gc;
};
下面我们使用Xdebug查看当某个变量被赋值通过引用时,refcount__gc与is_ref__gc在变量容器中的情况。
测试代码<?php $a = 'me';
xdebug_debug_zval('a');
$b = &$a;
xdebug_debug_zval('a');
xdebug_debug_zval('a');
$b = 'too'; 
var_dump($a);
unset($a);
xdebug_debug_zval('b');?> 程序输出的情况如下:
a: (refcount=1, is_ref=0)='me'
a: (refcount=2, is_ref=1)='me'
b: (refcount=2, is_ref=1)='me'
string(3) "too"
b: (refcount=1, is_ref=0)='too'
从上面的输出中,可以知道变量a,b共用同一个变量容器,当调用unset  销毁a时,只是改变变量容器的引用计数器,并没有
实际清除变量容器,而是取消相应的符号表条目与该变量映射并清除。
下面再看一个函数内部调用unset消费全局变量的情景,测试代码如下:
<?php
function test()
{
  global $a;
  xdebug_debug_zval('a');
  unset($a);
  xdebug_debug_zval('a');
}
$a = 'me';
xdebug_debug_zval('a');
test();
var_dump($a);
xdebug_debug_zval('a');
?>
运行输出的结果如下:
a: (refcount=1, is_ref=0)='me'
a: (refcount=2, is_ref=1)='me'
a: (refcount=1, is_ref=0)='me'
string(2) "me"
a: (refcount=1, is_ref=0)='me'
由上面的结果可以知道,当在函数内部引用全局变量时,会使全局变量对应的变量容器的引用计数器加一同时说明此变量被引用
过,类似与通过引用传递的变量情景,当在函数内部使用unset  销毁全局变量仅是将相应的引用计数器值以及是否引用做改变。
有时我也在想,当在函数内部调用全部变量会不会临时在符号表中添加新的一条目,符号标志也是' a',  只不过作用域是函数
内部,具体的情况还没来得及细看,有机会继续深入。
从上可以知道 unset  在撤销变量时,会对变量对应的变量容器操作, 同时撤销掉相应的符号表中的条目,至于内存是否
被销毁,需相应的计数器值为零,我将第一个例子的代码后面又添加三行代码,
unset($b);
echo 'over';
xdebug_debug_zval('b');
当程序运行后结果如下:
a: (refcount=1, is_ref=0)='me'
a: (refcount=2, is_ref=1)='me'
b: (refcount=2, is_ref=1)='me'
string(3) "too"
b: (refcount=1, is_ref=0)='too'
over
     由结果可以知道,当对变量b再使用unse时,就会使变量容器被销毁掉,既内存的值被清除掉,相应的内存块也被释放。

© 著作权归作者所有

粉丝 0
博文 5
码字总数 5859
作品 0
朝阳
私信 提问
php-------unset销毁变量并释放内存

PHP的unset()函数用来清除、销毁变量,不用的变量,我们可以用unset()将它销毁。但是某些时候,用unset()却无法达到销毁变量占用的内存! 我们先看一个例子: 最后输出unset()之前占用内存减...

切切歆语
2018/02/01
0
0
PHP unset销毁变量并释放内存

PHP的unset()函数用来清除、销毁变量,不用的变量,我们可以用unset()将它销毁。但是某些时候,用unset()却无法达到销毁变量占用的内存!我们先看一个例子: <?php $s=str_repeat('1',255); ...

本杰明刘能
2016/11/22
8
0
session_unset()和session_destroy()用法分析

关于sessionunset()和sessiondestroy()的函数使用进行介绍。 sessionunset() 释放当前在内存中已经创建的所有$SESSION变量,但不删除session文件以及不释放对应的session id sessiondestroy...

BearCatYN
2014/11/12
0
0
PHP中的魔术方法总结 :__construct, __destruct , __call, ...

1、get、set 这两个方法是为在类和他们的父类中没有声明的属性而设计的 get( $property ) 当调用一个未定义的属性时访问此方法 set( $property, $value ) 给一个未定义的属性赋值时调用 这里...

kisshua
2012/04/25
0
0
php中引用&的真正理解

原文地址:http://www.cnblogs.com/thinksasa/p/3334492.html php的引用(就是在变量或者函数、对象等前面加上&符号) //最重要就是 删除引用的变量 ,只是引用的变量访问不了,但是内容并没...

chenzy526
2017/05/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

进程命令ps

命令ps 用途: 显示当前系统的进程状态 语法: ]# ps [选项] 常用选项: aux = 列出正在运行的所有进程; a 显示现行终端机下的所有程序,包括其他用户的程序 u 以用户为主...

迷失De挣扎
49分钟前
3
0
聊聊spring cloud的CachingSpringLoadBalancerFactory

序 本文主要研究一下spring cloud的CachingSpringLoadBalancerFactory CachingSpringLoadBalancerFactory spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/o......

go4it
昨天
4
0
一篇文章搞定——JDK8中新增的StampedLock

一、StampedLock类简介 StampedLock类,在JDK1.8时引入,是对读写锁ReentrantReadWriteLock的增强,该类提供了一些功能,优化了读锁、写锁的访问,同时使读写锁之间可以互相转换,更细粒度控...

须臾之余
昨天
4
0
Android Camera原理之CameraDeviceCallbacks回调模块

在讲解《Android Camera原理之openCamera模块(二)》一文的时候提到了CameraDeviceCallbacks回调,当时没有详细展开,本文我们详细展开讲解一下。 CameraDeviceCallbacks生成过程: 《Android...

天王盖地虎626
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部