内存申请

ZendMM使用自身heap层申请内存追踪结果:

 ZEND_ASSIGN_SPEC_CV_CONST_HANDLER (......)
-> ALLOC_ZVAL(......)
-> ZEND_FAST_ALLOC(......)
-> emalloc (......)
-> _emalloc(......)
-> _zend_mm_alloc_int(.....)

  void *_emalloc 实现了对内存的申请操作,在_emalloc的处理过程中, 对是否使用ZendMM进行了判断,如果heap层没有使用ZendMM来管理, 就直接使用_zend_mm_heap结构中定义的_malloc函数进行内存的分配; (这里的_malloc可以是malloc,win32,mmap_anon,mmap_zero中的一种);

  ZendMM进行内存管理流程

  1. 内存检查。 对要申请的内存大小进行检查,如果太大(超出memory_limit则报 Out of Memory);
  2. 如果命中缓存,使用fastcache得到内存块,然后直接进行第5步;
  3. 在ZendMM管理的heap层存储中搜索合适大小的内存块, 在这一步骤ZendMM通过与ZEND_MM_MAX_SMALL_SIZE进行大小比较, 把内存请求分为两种类型: large和small。small类型的的请求会先使用zend_mm_low_bit函数 在mm_heap中的free_buckets中查找,未找到则使用与large类型相同的方式: 使用zend_mm_search_large_block函数在“大块”内存(_zend_mm_heap->large_free_buckets)中进行查找。 如果还没有可以满足大小需求的内存,最后在rest_buckets中进行查找。 也就是说,内存的分配是在三种列表中小到大进行的。 找到可以使用的block后,进行第5步;
  4. 如果经过第3步的查找还没有找到可以使用的资源(请求的内存过大),需要使用ZEND_MM_STORAGE_ALLOC函数向系统再申请一块内存(大小至少为ZEND_MM_SEG_SIZE),然后直接将对齐后的地址分配给本次请求。跳到第6步;
  5. 使用zend_mm_remove_from_free_list函数将已经使用block节点在zend_mm_free_block中移除;
  6. 内存分配完毕,对zend_mm_heap结构中的各种标识型变量进行维护,包括large_free_buckets, peak,size等;
  7. 返回分配的内存地址;

  PHP对内存的分配,是结合PHP的用途来设计的,PHP一般用于web应用程序的数据支持, 单个脚本的运行周期一般比较短(最多达到秒级),内存大块整块的申请,自主进行小块的分配, 没有进行比较复杂的不相临地址的空闲内存合并,而是集中再次向系统请求。 这样做的好处就是运行速度会更快,缺点是随着程序的运行时间的变长, 内存的使用情况会“越来越多”(PHP5.2及更早版本)。 所以PHP5.3之前的版本并不适合做为守护进程长期运行。 在PHP5.3中引入了新的GC(垃圾回收)机制。

内存销毁

  ZendMM在内存销毁的处理上采用与内存申请相同的策略,当程序unset一个变量或者是其他的释放行为时, ZendMM并不会直接立刻将内存交回给系统,而是只在自身维护的内存池中将其重新标识为可用, 按照内存的大小整理到上面所说的三种列表(small,large,free)之中,以备下次内存申请时使用。

  内存销毁的最终实现函数是_efree。在_efree中,内存的销毁首先要进行是否放回cache的判断。 如果内存的大小满足ZEND_MM_SMALL_SIZE并且cache还没有超过系统设置的ZEND_MM_CACHE_SIZE, 那么,当前内存块zend_mm_block就会被放回mm_heap->cache中。 如果内存块没有被放回cache,则使用下面的代码进行处理(Zend/zend_alloc.c):

        zend_mm_block *mm_block;//要销毁的内存块
zend_mm_block *next_block;
     size_t size;
     ...
next_block = ZEND_MM_BLOCK_AT(mm_block, size);
if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
}
if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) {
mm_block = ZEND_MM_PREV_BLOCK(mm_block);
zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block);
size += ZEND_MM_FREE_BLOCK_SIZE(mm_block);
}
if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(mm_block, size))) {
zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE));
} else {
ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size);
zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block);
}

  这段代码逻辑比较清晰,主要是根据当前要销毁的内存块mm_blockzend_mm_heap 双向链表中所处的位置进行不同的操作。如果下一个节点还是free的内存,则将下一个节点合并; 如果上一相邻节点内存块为free,则合并到上一个节点; 如果只是普通节点,刚使用 zend_mm_add_to_free_list或者zend_mm_del_segment 进行回收。

  就这样,ZendMM将内存块以整理收回到zend_mm_heap的方式,回收到内存池中。 程序使用的所有内存,将在进程结束时统一交还给系统。

php内存申请和销毁的更多相关文章

  1. Unity内存申请和释放

    转自:http://www.jianshu.com/p/b37ee8cea04c 1.资源类型 GameObject, Transform, Mesh, Texture, Material, Shad ...

  2. CE 内存申请

    char ch_ReadByte='H'; char *ptr_OneLineData; unsigned ); if ((ptr_OneLineData = (char *)malloc(bufsi ...

  3. JVM系列二:GC策略&内存申请、对象衰老

    JVM里的GC(Garbage Collection)的算法有很多种,如标记清除收集器,压缩收集器,分代收集器等等,详见HotSpot VM GC 的种类 现在比较常用的是分代收集(generatio ...

  4. 【转载】JVM系列二:GC策略&内存申请、对象衰老

    JVM里的GC(Garbage Collection)的算法有很多种,如标记清除收集器,压缩收集器,分代收集器等等,详见HotSpot VM GC 的种类 现在比较常用的是分代收集(generatio ...

  5. C++解析-外传篇(3):动态内存申请的结果

    0.目录 1.动态内存申请一定成功吗? 2.new_handler() 函数 3.小结 1.动态内存申请一定成功吗? 问题: 动态内存申请一定成功吗? 常见的动态内存分配代码: C代码: C++代码: ...

  6. glibc 内存申请和释放及堆连续检查

    C语言有两种内存申请方式: 1.静态申请:当你声明全局或静态变量的时候,会用到静态申请内存.静态申请的内存有固定的空间大小.空间只在程序开始的时候申请一次,并且不再释放(除非程序结束). 2.自动申请 ...

  7. C++函数中,两个自动释放内存的动态内存申请类

    最近做一个事情,实现一个流程交互,其中主交互流程函数中,涉及较多的内存申请, 而健康的函数,都是在函数退出前将手动申请不再需要的内存释放掉, 使用很多方法,都避免不了较多的出错分支时,一堆的if fr ...

  8. [转]JVM系列二:GC策略&内存申请、对象衰老

    原文地址:http://www.cnblogs.com/redcreen/archive/2011/05/04/2037056.html JVM里的GC(Garbage Collection)的算法有 ...

  9. C++中动态内存申请的结果

    1,问题: 1,动态内存申请一定成功吗? 1,不一定成功: 2,常见的动态内存分配代码: 1,C 代码: * sizeof(int)); if( p != NULL ) { // ... ... } ...

随机推荐

  1. UVA 110 Meta-Loopless Sorts(输出挺麻烦的。。。)

     Meta-Loopless Sorts  Background Sorting holds an important place in computer science. Analyzing and ...

  2. Ajax之旅(一)--什么是Ajax

    本来在学习DRP,但是无意中发现所附资料中有一些參考书籍,当中就有一个关于Ajax的,看了看,挺好的,于是决定暂停一下DRP,再次学习一下Ajax.记得第一遍学习Ajax的时候认为真的是一团雾水,看了 ...

  3. Python重写C语言程序100例--Part1

    ''' [程序1] 题目:有1.2.3.4个数字,能组成多少个互不同样且无反复数字的三位数?都是多少? 1.程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成全部的排列后再去 掉不满足条件 ...

  4. PHP【第一篇】安装

    一.准备 1.环境 系统平台:Red Hat Enterprise Linux Server release 7.3 (Maipo) 内核版本:3.10.0-514.el7.x86_64 2.下载安装 ...

  5. Android(java)学习笔记164:Relativelayout相对布局案例

    我们看看案例代码,自己心领神会: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout ...

  6. 删除sd卡的文件

    public static void deleteAllFile(){ String path = Environment.getExternalStorageDirectory().getAbsol ...

  7. 解析XML文件时做得修改

    在.h文件中找到需要在Build Settings中设置的东西,查找Header Search Paths,然后添加/usr/include/libxml2

  8. Find Security Bugs研究,邀请志同道合者一起参与

    Find Security Bugs研究,邀请志同道合者一起参与http://automationqa.com/forum.php?mod=viewthread&tid=2803&fr ...

  9. Flume简介与使用(一)——Flume安装与配置

    Flume简介与使用(一)——Flume安装与配置 Flume简介 Flume是一个分布式的.可靠的.实用的服务——从不同的数据源高效的采集.整合.移动海量数据. 分布式:可以多台机器同时运行采集数据 ...

  10. 【排障】使用DiskGenius修复0扇区损坏

    用PE引导启动进入PE后打开DiskGenius软件 "硬盘"图形菜单------选择驱动器符号(例如C) 主界面中显示该硬盘的分区格式为FAT32,起始柱面0,起始磁头65. 在 ...