[李景山php] 深入理解PHP内核[读书笔记]--第六章:内存管理

49 篇文章 0 订阅

内存管理的主要工作是尽可能的高效的利用内存。

php如果频繁的调用内存,会导致系统在内核态和用户态直接切换会产生性能问题。

如果在php一次读取超大的文件,容易造成内存不够用。默认的php内存大小是32M,可以通过php.ini调整内存大小。

可以通过 memory_get_usage() 及 memory_get_peak_usage() 分别来获取对应的内存使用值,及峰值情况。

uset是个好东西。

PHP的内存管理


PHP的内存管理可以被看作是分层(hierarchical)的。它分为三层:存储层(storage)、堆层(heap)和接口层(emalloc/efree)。存储层通过 malloc()、mmap() 等函数向系统真正的申请内存,并通过 free() 函数释放所申请的内存。存储层通常申请的内存块都比较大,这里申请的内存大并不是指storage层结构所需要的内存大,只是堆层通过调用存储层的分配方法时,其以大块大块的方式申请的内存,存储层的作用是将内存分配的方式对堆层透明化。

PHP的内存申请


PHP底层对内存的管理,围绕着小块内存列表(free_buckets)、 大块内存列表(large_free_buckets)和剩余内存列表(rest_buckets)三个列表来分层进行的。 ZendMM向系统进行的内存申请,并不是有需要时向系统即时申请,而是由ZendMM的最底层(heap层)先向系统申请一大块的内存,通过对上面三种列表的填充,建立一个类似于内存池的管理机制。在程序运行需要使用内存的时候,ZendMM会在内存池中分配相应的内存供使用。这样做的好处是避免了PHP向系统频繁的内存申请操作,如下操作:

php 内存的消耗


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

内存销毁的最终实现函数是_efree。在_efree中,内存的销毁首先要进行是否放回cache的判断。

php5.3之后的新的垃圾回收机制


之前就是简单的引用计数,然后回收,现在是这样的。

在zval字段后面有一个联合体:u。 u包括gc_root_buffer结构的buffered字段和zval_gc_info结构的next字段。这两个字段一个是表示垃圾收集机制缓存的根结点,一个是zval_gc_info列表的下一个结点,垃圾收集机制缓存的结点无论是作为根结点,还是列表结点,都可以在这里体现。 ALLOC_ZVAL在分配了内存后会调用GC_ZVAL_INIT用来初始化替代了zval的zval_gc_info,它会把zval_gc_info中的成员u的buffered字段设置成NULL,此字段仅在将其放入垃圾回收缓冲区时才会有值,否则会一直是NULL。由于PHP中所有的变量都是以zval变量的形式存在,这里以zval_gc_info替换zval,从而成功实现垃圾收集机制在原有系统中的集成。

php 内存管理中的缓存


* 标识缓存和缓存的大小限制,即何时使用缓存,在某些情况下可以以最少的修改禁用掉缓存
* 缓存的存储结构,即缓存的存放位置、结构和存放的逻辑
* 初始化缓存
* 获取缓存中内容
* 写入缓存
* 释放缓存或者清空缓存列表

php 写时复制


内存泄漏


内存泄漏指的是在程序运行过程中申请了内存,但是在使用完成后没有及时释放的现象,对于普通运行时间较短的程序来说可能问题不会那么明显,但是对于长时间运行的程序,比如Web服务器,后台进程等就比较明显了,随着系统运行占用的内存会持续上升,可能会因为占用内存过高而崩溃,或被系统杀掉(OOM)。

PHP属于高级语言,语言级别并没有内存的概念,在使用过程中完全不需要主动申请或释放内存,所以在PHP用户代码级别也就不存在内存泄漏的概念了。
但毕竟PHP是使用C编写的解释器,所以本质上还是一样的,那么可以这么说:如果你的PHP程序内存泄漏了,肯定不是你的错,而是PHP实现的错:),

如果发现php内存泄漏,可以通过打开 enable-debug 方式打开。

PHP本身有自己的内存管理,如果发现PHP有内存泄漏,可以尝试重新编译一个PHP,将编译选项–enable-debug打开(同时所有的扩展也同样需要编译成支持debug模式的): ./configure –enable-debug,这样重新编译后,如果PHP探测到有内存泄漏发生则会往 标准错误输出 打印错误信息。这样我们可以快速的发现问题。

在开启debug模式下,PHP中会有一个函数leak()可以用于触发内存泄漏,这个函数什么都不做,只是申请一块内存但不释放,其实现很简单。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值