释放内存现在显示为负数,本期还需还款额为负数释放吗

85被浏览40102分享邀请回答3添加评论分享收藏感谢收起2719 条评论分享收藏感谢收起经验1394 米
在线时间239 小时
版本V8.5.7.0.NDECNEF
积分 1857, 距离下一级还需 143 积分
积分 1857, 距离下一级还需 143 积分
机型小米MIX 2
签到次数32
MIUI版本V8.5.7.0.NDECNEF
如题...安卓一个40多M的游戏提示我内存不足啊...怎么回事?明明还有很多容量啊...求解...
分享到微信朋友圈
打开微信,点击底部的“发现”,使用 “扫一扫” 即可将网页分享到我的朋友圈。
经验3638 米
在线时间368 小时
积分 4157, 距离下一级还需 843 积分
积分 4157, 距离下一级还需 843 积分
机型小米手机2/2S
签到次数105
MIUI版本4.8.8
是不是正在运行的程序太多了,大量地占用内存(一般所说的运存),长按小房子键,清理正在运行的程序,再运行游戏看看。
你说的内存空间和游戏提供的内存是两个不同概念,前者是指机身存储空间,类似计算机的系统盘,后者指的是运行内存,类似计算机的内存。
水平有限,不周之处还望指出!企鹅:201604
有同样问题的机油请围观:
经验1394 米
在线时间239 小时
版本V8.5.7.0.NDECNEF
积分 1857, 距离下一级还需 143 积分
积分 1857, 距离下一级还需 143 积分
机型小米MIX 2
签到次数32
MIUI版本V8.5.7.0.NDECNEF
郁闷了...清理了一次还是不行啊...
Screenshot_-15-58-21.png (55.91 KB, 下载次数: 0)
经验1394 米
在线时间239 小时
版本V8.5.7.0.NDECNEF
积分 1857, 距离下一级还需 143 积分
积分 1857, 距离下一级还需 143 积分
机型小米MIX 2
签到次数32
MIUI版本V8.5.7.0.NDECNEF
就是出现这个..
在线时间2 小时
版本ICS24.0
积分 44, 距离下一级还需 6 积分
积分 44, 距离下一级还需 6 积分
机型小米手机1/1S
MIUI版本ICS24.0
这个一看就是FLASH空间不够了挖,弄个TF卡
经验1394 米
在线时间239 小时
版本V8.5.7.0.NDECNEF
积分 1857, 距离下一级还需 143 积分
积分 1857, 距离下一级还需 143 积分
机型小米MIX 2
签到次数32
MIUI版本V8.5.7.0.NDECNEF
郁闷...我TF卡16G的啊..还剩有5G多呢~~
在线时间2 小时
版本ICS24.0
积分 44, 距离下一级还需 6 积分
积分 44, 距离下一级还需 6 积分
机型小米手机1/1S
MIUI版本ICS24.0
你装在ROM里的估计,ROM空间不足了,你把你的存储空间贴出来看看
经验2887 米
在线时间125 小时
版本5.2.13
积分 3194, 距离下一级还需 1806 积分
积分 3194, 距离下一级还需 1806 积分
机型未知设备
签到次数95
MIUI版本5.2.13
进入data/app文件夹。
把有关这个游戏的所有文件全部删掉再装试试
经验1394 米
在线时间239 小时
版本V8.5.7.0.NDECNEF
积分 1857, 距离下一级还需 143 积分
积分 1857, 距离下一级还需 143 积分
机型小米MIX 2
签到次数32
MIUI版本V8.5.7.0.NDECNEF
ROM里面也还有1G多啊,,,
经验20016 米
在线时间922 小时
版本7.7.20
机型小米手机5
签到次数147
MIUI版本7.7.20
通过手机发布
qinxuanjia 发表于
回复 mmxfmmc 的帖子
ROM里面也还有1G多啊,,,
用re管理器进入/data/app/删除所有后缀为odex的文件即可
MIUI 2000万
MIUI 2000万发烧友纪念勋章
MIUI三周年
MIUI三周年纪念勋章
关注腾讯微博
已关注腾讯微博
关注新浪微博
已关注新浪微博
MIUI 100周
100周发布纪念勋章
1000万用户纪念勋章
MIUI1000万用户纪念勋章
已关注极客秀微信
已关注微信
百万壁纸评审纪念勋章
发烧友俱乐部
发烧友俱乐部
Copyright (C) 2017 MIUI
京ICP备号 | 京公网安备34号 | 京ICP证110507号 |  |  |  |  |  | 
热门搜索:
您所在的位置: >
> 内存释放专家 V1.21绿色版
内存释放专家 V1.21绿色版 能够有效释放应用程序在运行时未能及时释放的内存资源
软件大小:260.9 KB
软件类型:国产软件
软件分类: /
软件语言:简体中文
软件授权:免费软件
更新时间:
支持系统:Vista/winXP/win7/win8
相关链接:
相关合集:
热门专题:
手机扫一扫快捷方便下载
本类应用推荐
功能强大的内存修改工具
V5.4 汉化版
V1.0 简体中文绿色免费版
强大的内存历遍软件
V1.0 官方免费绿色版
软件可以支持定时释放内存、非常方便
V1.0绿色中文免费版
内存虚拟为硬盘
V1.1 中文绿色版
功能强大的极品内存检测软件
V5.10 绿色英文版
系统工具排行榜
驱动相关 | 
一款多功能的驱动管理和维护工具
硬件相关 | 
一款好用的自动安装驱动程序
磁盘工具 | 
一款将电脑的物理内存虚拟成硬盘缓存的工具
驱动相关 | 
一款好用的智能检测系统驱动的软件
备份还原 | 
一款好用的系统备份与还原软件
卸载清除 | 
一款功能强大的的有效卸载工具
卸载清除 | 
一款操作简单的注册表维护工具
磁盘工具 | 
一款功能强大的分区管理和数据恢复软件
内存释放专家能够有效释放应用程序在运行时未能及时释放的内存资源,并提供给需要使用大量内存的程序使用。它在释放内存时不会加重系统负担,保证系统运行流畅。(建议勿将定时释放间隔时间设置得太小
,软件?软件下载后?飞翔小编十二分诚意等待着您的投诉与建议
APK文件怎么打开,下载APK文件如何安装到手机?推荐使用
软件无法下载
下载后无法使用
与描述不一致
你的空调我做主
荒野行动辅助大全
2017全年手游风
2017新手游排行榜
星球大战手游排
几维遥控器是一款操作简单便捷的随身万能遥控器软件,用户可通过几维遥控器app将你的手机变成万能遥控器,妈妈再也不担心我找不到遥控器了,有需要的小伙伴快来下载体验吧!...
你可能还喜欢
一款全面的清理工具,可以释放内存清理进程,支持定时清理,还可以清理系统缓存,支持桌面插件一键清理。
却媲謇怼Clean ★ Memory Cleaner】:简洁的内存碎片整理软件,能够清洁优化内存,提高运行速度,清除内存和缓存文件,以减少工作负载和CPU的压力
内存清理大师
52z飞翔下载网小编在这里为大家整理了娜娜草nana软件合集,提供娜娜草nana手机播放器下载。娜娜草nana是一款非常好用的在线视频播放软件,海量高清视频资源,超级好用。不管你想看什么,就可以轻松观看你想看的视频,高清画质完全无损,让你轻松观看追剧更省心!
52z飞翔下载网小编在这里为大家整理了全色资源网APP合集,提供全色资源网在线观看、全色资源网视频资源下载、全色资源网APP下载。全色资源网是一款专为电影爱好者打造的看片神器,支持免费无广告、本地缓存离线观看等功能,为用户提供电影、电视剧、综艺、动漫等丰富的高清视频内容。
52z飞翔下载网小编在这里为大家整理了史上第一内涵游戏游戏合集,提供史上第一内涵游戏安卓版/ios版/破解版下载以及史上第一内涵游戏攻略。史上第一内涵游戏是一款非常经典的益智休闲类手机游戏,该游戏拥有着全新的玩法、炫酷的特效和精美的游戏画面设计。感兴趣的小伙伴们快来下载试玩吧!
52z飞翔下载网小编在这里为各位微信用户整理了2018微信抢红包软件合集,提供2018微信抢红包神器下载。这里有最专业的微信红包助手软件,一键快速秒抢,支持自动抢红包,安全稳定,想想以后不会再错过大额红包是不是很激动?快来下载吧。
过年过节最让人兴奋的就是抢红包了,有时候手机不在身边不要紧,下载一款抢红包软件就可以了。52z飞翔下载网小编在这里就为各位整理了2018抢红包软件合集,提供2018微信qq抢红包神器下载。这些最新的抢红包软件,不仅继承了经典的抢红包玩法,还加入了许多新颖的元素,感兴趣的伙伴们快来下载体验吧~
喜欢看小说的小伙伴有福了,52z飞翔下载网小编在这里为各位小说迷整理了2018手机小说阅读器合集,提供2018最新手机小说阅读器下载。这些手机小说阅读器为广大读者提供更新更多更优质的小说,让读者在阅读中体会读书与小说的无穷魅力。感兴趣的小伙伴快来下载吧!
进入手机版深入探讨PHP中的内存管理问题
- ThinkPHP框架
深入探讨PHP中的内存管理问题
, 收集与网络不知道原作者!一、&内存
  在PHP中,填充一个字符串变量相当简单,这只需要一个语句"<?php&$str&=&'hello&world&';&?>"即可,并且该字符串能够被自由地修改、拷贝和移动。而在C语言中,尽管你能够编写例如"char&*str&=&"hello&world&";"这样的一个简单的静态字符串;但是,却不能修改该字符串,因为它生存于程序空间内。为了创建一个可操纵的字符串,你必须分配一个内存块,并且通过一个函数(例如strdup())来复制其内容。
 str&=&strdup("hello&world");
 if&(!str)&{
  fprintf(stderr,&"Unable&to&allocate&memory!");
  由于后面我们将分析的各种原因,传统型内存管理函数(例如malloc(),free(),strdup(),realloc(),calloc(),等等)几乎都不能直接为PHP源代码所使用。
  二、&释放内存
  在几乎所有的平台上,内存管理都是通过一种请求和释放模式实现的。首先,一个应用程序请求它下面的层(通常指"操作系统"):"我想使用一些内存空间"。如果存在可用的空间,操作系统就会把它提供给该程序并且打上一个标记以便不会再把这部分内存分配给其它程序。
当应用程序使用完这部分内存,它应该被返回到OS;这样以来,它就能够被继续分配给其它程序。如果该程序不返回这部分内存,那么OS无法知道是否这块内存不再使用并进而再分配给另一个进程。如果一个内存块没有释放,并且所有者应用程序丢失了它,那么,我们就说此应用程序"存在漏洞",因为这部分内存无法再为其它程序可用。
  在一个典型的客户端应用程序中,较小的不太经常的内存泄漏有时能够为OS所"容忍",因为在这个进程稍后结束时该泄漏内存会被隐式返回到OS。这并没有什么,因为OS知道它把该内存分配给了哪个程序,并且它能够确信当该程序终止时不再需要该内存。
  而对于长时间运行的服务器守护程序,包括象Apache这样的web服务器和扩展php模块来说,进程往往被设计为相当长时间一直运行。因为OS不能清理内存使用,所以,任何程序的泄漏-无论是多么小-都将导致重复操作并最终耗尽所有的系统资源。
  现在,我们不妨考虑用户空间内的stristr()函数;为了使用大小写不敏感的搜索来查找一个字符串,它实际上创建了两个串的各自的一个小型副本,然后执行一个更传统型的大小写敏感的搜索来查找相对的偏移量。然而,在定位该字符串的偏移量之后,它不再使用这些小写版本的字符串。如果它不释放这些副本,那么,每一个使用stristr()的脚本在每次调用它时都将泄漏一些内存。最后,web服务器进程将拥有所有的系统内存,但却不能够使用它。
  你可以理直气壮地说,理想的解决方案就是编写良好、干净的、一致的代码。这当然不错;但是,在一个象PHP解释器这样的环境中,这种观点仅对了一半。
  三、&错误处理
  为了实现"跳出"对用户空间脚本及其依赖的扩展函数的一个活动请求,需要使用一种方法来完全"跳出"一个活动请求。这是在Zend引擎内实现的:在一个请求的开始设置一个"跳出"地址,然后在任何die()或exit()调用或在遇到任何关键错误(E_ERROR)时执行一个longjmp()以跳转到该"跳出"地址。
  尽管这个"跳出"进程能够简化程序执行的流程,但是,在绝大多数情况下,这会意味着将会跳过资源清除代码部分(例如free()调用)并最终导致出现内存漏洞。现在,让我们来考虑下面这个简化版本的处理函数调用的引擎代码:
void&call_function(const&char&*fname,&int&fname_len&TSRMLS_DC){
 zend_function&*
 char&*lcase_
 /*&PHP函数名是大小写不敏感的,
 *为了简化在函数表中对它们的定位,
 *所有函数名都隐含地翻译为小写的
 lcase_fname&=&estrndup(fname,&fname_len);
 zend_str_tolower(lcase_fname,&fname_len);
 if&(zend_hash_find(EG(function_table),lcase_fname,&fname_len&+&1,&(void&**)&fe)&==&FAILURE)&{
  zend_execute(fe->op_array&TSRMLS_CC);
 }&else&{
  php_error_docref(NULL&TSRMLS_CC,&E_ERROR,"Call&to&undefined&function:&%s()",&fname);
 efree(lcase_fname);
  当执行到php_error_docref()这一行时,内部错误处理器就会明白该错误级别是critical,并相应地调用longjmp()来中断当前程序流程并离开call_function()函数,甚至根本不会执行到efree(lcase_fname)这一行。你可能想把efree()代码行移动到zend_error()代码行的上面;但是,调用这个call_function()例程的代码行会怎么样呢?fname本身很可能就是一个分配的字符串,并且,在它被错误消息处理使用完之前,你根本不能释放它。
  注意,这个php_error_docref()函数是trigger_error()函数的一个内部等价实现。它的第一个参数是一个将被添加到docref的可选的文档引用。第三个参数可以是任何我们熟悉的E_*家族常量,用于指示错误的严重程度。第四个参数(最后一个)遵循printf()风格的格式化和变量参数列表式样。
  四、&Zend内存管理器
  在上面的"跳出"请求期间解决内存泄漏的方案之一是:使用Zend内存管理(ZendMM)层。引擎的这一部分非常类似于操作系统的内存管理行为-分配内存给调用程序。区别在于,它处于进程空间中非常低的位置而且是"请求感知"的;这样以来,当一个请求结束时,它能够执行与OS在一个进程终止时相同的行为。也就是说,它会隐式地释放所有的为该请求所占用的内存。图1展示了ZendMM与OS以及PHP进程之间的关系。
深入探讨PHP中的内存管理问题
图1.Zend内存管理器代替系统调用来实现针对每一种请求的内存分配。
  除了提供隐式内存清除功能之外,ZendMM还能够根据php.ini中memory_limit的设置控制每一种内存请求的用法。如果一个脚本试图请求比系统中可用内存更多的内存,或大于它每次应该请求的最大量,那么,ZendMM将自动地发出一个E_ERROR消息并且启动相应的"跳出"进程。这种方法的一个额外优点在于,大多数内存分配调用的返回值并不需要检查,因为如果失败的话将会导致立即跳转到引擎的退出部分。
  把PHP内部代码和OS的实际的内存管理层"钩"在一起的原理并不复杂:所有内部分配的内存都要使用一组特定的可选函数实现。例如,PHP代码不是使用malloc(16)来分配一个16字节内存块而是使用了emalloc(16)。除了实现实际的内存分配任务外,ZendMM还会使用相应的绑定请求类型来标志该内存块;这样以来,当一个请求"跳出"时,ZendMM可以隐式地释放它。
  经常情况下,内存一般都需要被分配比单个请求持续时间更长的一段时间。这种类型的分配(因其在一次请求结束之后仍然存在而被称为"永久性分配"),可以使用传统型内存分配器来实现,因为这些分配并不会添加ZendMM使用的那些额外的相应于每种请求的信息。然而有时,直到运行时刻才会确定是否一个特定的分配需要永久性分配,因此ZendMM导出了一组帮助宏,其行为类似于其它的内存分配函数,但是使用最后一个额外参数来指示是否为永久性分配。
  如果你确实想实现一个永久性分配,那么这个参数应该被设置为1;在这种情况下,请求是通过传统型malloc()分配器家族进行传递的。然而,如果运行时刻逻辑认为这个块不需要永久性分配;那么,这个参数可以被设置为零,并且调用将会被调整到针对每种请求的内存分配器函数。
  例如,pemalloc(buffer_len,1)将映射到malloc(buffer_len),而pemalloc(buffer_len,0)将被使用下列语句映射到emalloc(buffer_len):
#define&in&Zend/zend_alloc.h:
#define&pemalloc(size,&persistent)&((persistent)?malloc(size):&emalloc(size))
  所有这些在ZendMM中提供的分配器函数都能够从下表中找到其更传统的对应实现。
  表格1展示了ZendMM支持下的每一个分配器函数以及它们的e/pe对应实现:
  表格1.传统型相对于PHP特定的分配器。
分配器函数&&&&e/pe对应实现
void&*malloc(size_t&count);&&&&void&*emalloc(size_t&count);void&*pemalloc(size_t&count,char&persistent);
void&*calloc(size_t&count);&&&&void&*ecalloc(size_t&count);void&*pecalloc(size_t&count,char&persistent);
void&*realloc(void&*ptr,size_t&count);&&&&void&*erealloc(void&*ptr,size_t&count);
void&*perealloc(void&*ptr,size_t&count,char&persistent);
void&*strdup(void&*ptr);&&&&void&*estrdup(void&*ptr);void&*pestrdup(void&*ptr,char&persistent);
void&free(void&*ptr);&&&&void&efree(void&*ptr);
void&pefree(void&*ptr,char&persistent);
  你可能会注意到,即使是pefree()函数也要求使用永久性标志。这是因为在调用pefree()时,它实际上并不知道是否ptr是一种永久性分配。针对一个非永久性分配调用free()能够导致双倍的空间释放,而针对一种永久性分配调用efree()有可能会导致一个段错误,因为内存管理器会试图查找并不存在的管理信息。因此,你的代码需要记住它分配的数据结构是否是永久性的。&
  除了分配器函数核心部分外,还存在其它一些非常方便的ZendMM特定的函数,例如:
void&*estrndup(void&*ptr,int&len);
  该函数能够分配len+1个字节的内存并且从ptr处复制len个字节到最新分配的块。这个estrndup()函数的行为可以大致描述如下:
void&*estrndup(void&*ptr,&int&len)
 char&*dst&=&emalloc(len&+&1);
 memcpy(dst,&ptr,&len);
 dst[len]&=&0;
  在此,被隐式放置在缓冲区最后的NULL字节可以确保任何使用estrndup()实现字符串复制操作的函数都不需要担心会把结果缓冲区传递给一个例如printf()这样的希望以为NULL为结束符的函数。当使用estrndup()来复制非字符串数据时,最后一个字节实质上都浪费了,但其中的利明显大于弊。
void&*safe_emalloc(size_t&size,&size_t&count,&size_t&addtl);
void&*safe_pemalloc(size_t&size,&size_t&count,size_t&addtl,char&persistent);
  这些函数分配的内存空间最终大小是((size*count)+addtl)。你可以会问:"为什么还要提供额外函数呢?为什么不使用一个emalloc/pemalloc呢?"原因很简单:为了安全。尽管有时候可能性相当小,但是,正是这一"可能性相当小"的结果导致宿主平台的内存溢出。这可能会导致分配负数个数的字节空间,或更有甚者,会导致分配一个小于调用程序要求大小的字节空间。而safe_emalloc()能够避免这种类型的陷井-通过检查整数溢出并且在发生这样的溢出时显式地预以结束。
  注意,并不是所有的内存分配例程都有一个相应的p*对等实现。例如,不存在pestrndup(),并且在PHP&5.1版本前也不存在safe_pemalloc()。
  五、&引用计数
  慎重的内存分配与释放对于PHP(它是一种多请求进程)的长期性能有极其重大的影响;但是,这还仅是问题的一半。为了使一个每秒处理上千次点击的服务器高效地运行,每一次请求都需要使用尽可能少的内存并且要尽可能减少不必要的数据复制操作。请考虑下列PHP代码片断:
$a&=&'Hello&World';
unset($a);
  在第一次调用之后,只有一个变量被创建,并且一个12字节的内存块指派给它以便存储字符串"Hello&World",还包括一个结尾处的NULL字符。现在,让我们来观察后面的两行:$b被置为与变量$a相同的值,然后变量$a被释放。
  如果PHP因每次变量赋值都要复制变量内容的话,那么,对于上例中要复制的字符串还需要复制额外的12个字节,并且在数据复制期间还要进行另外的处理器加载。这一行为乍看起来有点荒谬,因为当第三行代码出现时,原始变量被释放,从而使得整个数据复制显得完全不必要。其实,我们不妨再远一层考虑,让我们设想当一个10MB大小的文件的内容被装载到两个变量中时会发生什么。这将会占用20MB的空间,此时,10已经足够了。引擎会把那么多的时间和内存浪费在这样一种无用的努力上吗?
  你应该知道,PHP的设计者早已深谙此理。
  记住,在引擎中,变量名和它们的值实际上是两个不同的概念。值本身是一个无名的zval*存储体(在本例中,是一个字符串值),它被通过zend_hash_add()赋给变量$a。如果两个变量名都指向同一个值,会发生什么呢?
 MAKE_STD_ZVAL(helloval);
 ZVAL_STRING(helloval,&"Hello&World",&1);
 zend_hash_add(EG(active_symbol_table),&"a",&sizeof("a"),&helloval,&sizeof(zval*),&NULL);
 zend_hash_add(EG(active_symbol_table),&"b",&sizeof("b"),&helloval,&sizeof(zval*),&NULL);
  此时,你可以实际地观察$a或$b,并且会看到它们都包含字符串"Hello&World"。遗憾的是,接下来,你继续执行第三行代码"unset($a);"。此时,unset()并不知道$a变量指向的数据还被另一个变量所使用,因此它只是盲目地释放掉该内存。任何随后的对变量$b的存取都将被分析为已经释放的内存空间并因此导致引擎崩溃。
  这个问题可以借助于zval(它有好几种形式)的第四个成员refcount加以解决。当一个变量被首次创建并赋值时,它的refcount被初始化为1,因为它被假定仅由最初创建它时相应的变量所使用。当你的代码片断开始把helloval赋给$b时,它需要把refcount的值增加为2;这样以来,现在该值被两个变量所引用:&
 MAKE_STD_ZVAL(helloval);
 ZVAL_STRING(helloval,&"Hello&World",&1);
 zend_hash_add(EG(active_symbol_table),&"a",&sizeof("a"),&helloval,&sizeof(zval*),&NULL);
 ZVAL_ADDREF(helloval);
 zend_hash_add(EG(active_symbol_table),&"b",&sizeof("b"),&helloval,sizeof(zval*),NULL);
  现在,当unset()删除原变量的$a相应的副本时,它就能够从refcount参数中看到,还有另外其他人对该数据感兴趣;因此,它应该只是减少refcount的计数值,然后不再管它。
  六、&写复制(Copy&on&Write)
  通过refcounting来节约内存的确是不错的主意,但是,当你仅想改变其中一个变量的值时情况会如何呢?为此,请考虑下面的代码片断:
  通过上面的逻辑流程,你当然知道$a的值仍然等于1,而$b的值最后将是6。并且此时,你还知道,Zend在尽力节省内存-通过使$a和$b都引用相同的zval(见第二行代码)。那么,当执行到第三行并且必须改变$b变量的值时,会发生什么情况呢?
  回答是,Zend要查看refcount的值,并且确保在它的值大于1时对之进行分离。在Zend引擎中,分离是破坏一个引用对的过程,正好与你刚才看到的过程相反:
zval&*get_var_and_separate(char&*varname,&int&varname_len&TSRMLS_DC)
 zval&**varval,&*
 if&(zend_hash_find(EG(active_symbol_table),varname,&varname_len&+&1,&(void**)&varval)&==&FAILURE)&{
  /*&变量根本并不存在-失败而导致退出*/
  return&NULL;
 if&((*varval)->refcount&<&2)&{
  /*&varname是唯一的实际引用,
  *不需要进行分离
  return&*
 /*&否则,再复制一份zval*的值*/
 MAKE_STD_ZVAL(varcopy);
 varcopy&=&*
 /*&复制任何在zval*内的已分配的结构*/
 zval_copy_ctor(varcopy);
 /*删除旧版本的varname
 *这将减少该过程中varval的refcount的值
 zend_hash_del(EG(active_symbol_table),&varname,&varname_len&+&1);
 /*初始化新创建的值的引用计数,并把它依附到
 *&varname变量
 varcopy->refcount&=&1;
 varcopy->is_ref&=&0;
 zend_hash_add(EG(active_symbol_table),&varname,&varname_len&+&1,&varcopy,&sizeof(zval*),&NULL);
 /*返回新的zval*&*/
  现在,既然引擎有一个仅为变量$b所拥有的zval*(引擎能知道这一点),所以它能够把这个值转换成一个long型值并根据脚本的请求给它增加5。
  七、&写改变(change-on-write)
  引用计数概念的引入还导致了一个新的数据操作可能性,其形式从用户空间脚本管理器看来与"引用"有一定关系。请考虑下列的用户空间代码片断:
  在上面的PHP代码中,你能看出$a的值现在为6,尽管它一开始为1并且从未(直接)发生变化。之所以会发生这种情况是因为当引擎开始把$b的值增加5时,它注意到$b是一个对$a的引用并且认为"我可以改变该值而不必分离它,因为我想使所有的引用变量都能看到这一改变"。
  但是,引擎是如何知道的呢?很简单,它只要查看一下zval结构的第四个和最后一个元素(is_ref)即可。这是一个简单的开/关位,它定义了该值是否实际上是一个用户空间风格引用集的一部分。在前面的代码片断中,当执行第一行时,为$a创建的值得到一个refcount为1,还有一个is_ref值为0,因为它仅为一个变量($a)所拥有并且没有其它变量对它产生写引用改变。在第二行,这个值的refcount元素被增加为2,除了这次is_ref元素被置为1之外(因为脚本中包含了一个"&"符号以指示是完全引用)。
  最后,在第三行,引擎再一次取出与变量$b相关的值并且检查是否有必要进行分离。这一次该值没有被分离,因为前面没有包括一个检查。下面是get_var_and_separate()函数中与refcount检查有关的部分代码:
if&((*varval)->is_ref&||&(*varval)->refcount&<&2)&{
 /*&varname是唯一的实际引用,
 *&或者它是对其它变量的一个完全引用
 *任何一种方式:都没有进行分离
 return&*
  这一次,尽管refcount为2,却没有实现分离,因为这个值是一个完全引用。引擎能够自由地修改它而不必关心其它变量值的变化。
  八、&分离问题
  尽管已经存在上面讨论到的复制和引用技术,但是还存在一些不能通过is_ref和refcount操作来解决的问题。请考虑下面这个PHP代码块:
  在此,你有一个需要与三个不同的变量相关联的值。其中,两个变量是使用了"change-on-write"完全引用方式,而第三个变量处于一种可分离的"copy-on-write"(写复制)上下文中。如果仅使用is_ref和refcount来描述这种关系,有哪些值能够工作呢?
  回答是:没有一个能工作。在这种情况下,这个值必须被复制到两个分离的zval*中,尽管两者都包含完全相同的数据(见图2)。
深入探讨PHP中的内存管理问题
图2.引用时强制分离
  同样,下列代码块将引起相同的冲突并且强迫该值分离出一个副本(见图3)。
深入探讨PHP中的内存管理问题
图3.复制时强制分离
  注意,在这里的两种情况下,$b都与原始的zval对象相关联,因为在分离发生时引擎无法知道介于到该操作当中的第三个变量的名字。
  九、&总结
  PHP是一种托管语言。从普通用户角度来看,这种仔细地控制资源和内存的方式意味着更为容易地进行原型开发并导致出现更少的冲突。然而,当我们深入"内里"之后,一切的承诺似乎都不复存在,最终还要依赖于真正有责任心的开发者来维持整个运行时刻环境的一致性。
chunguang_
积分:5012
ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架 ,创立于2006年初,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,已经成长为国内最领先和最具影响力的WEB应用开发框架,众多的典型案例确保可以稳定用于商业以及门户级的开发。}

我要回帖

更多关于 负数在内存中的存储 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信