Home php教程 php手册 PHP原理之内存管理中难懂的几个点

PHP原理之内存管理中难懂的几个点

Jun 21, 2016 am 08:53 AM
free index size zend

  PHP的内存管理, 分为俩大部分, 第一部分是PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用的层面的管理. 而第二部分就是今天我要介绍的, zend_alloc中描写的关于PHP自身的内存管理, 包括它是如何管理可用内存, 如何分配内存等.

  另外, 为什么要写这个呢, 因为之前并没有任何资料来介绍PHP内存管理中使用的策略, 数据结构, 或者算法. 而在我们平时开发扩展, 修复PHP的bug的时候, 却对这一部分的知识需要有一个良好的理解. PHP开发组内的很多朋友也对这块不是很清楚, 所以我觉得有必要专门写一下.

  一些基本的概念, 我就不赘述了, 因为看代码很容易能看懂, 我这里就主要介绍几个看代码没那么容易看懂的点, 为什么这么说呢, 呵呵, 我在写文章之前, 查找了下已有的资料, 已避免重复功, 其中看到了TIPI项目对这部分的描述, 发现其中错误很多. 所以, 我想这部分就是看代码也没那么容易看懂的点

  目前, 英文版的介绍也在撰写中: Zend MM

  Zend Memory Manager, 以下简称Zend MM, 是PHP中内存管理的逻辑. 其中有一个关键数据结构: zend_mm_heap:

  

 

  Zend MM把内存非为小块内存和大块内存俩种, 区别对待, 对于小块内存, 这部分是最最常用的, 所以追求高性能. 而对于大块内存, 则追求的是稳妥, 尽量避免内存浪费.

  所以, 对于小块内存, PHP还引入了cache机制:

  

 

  Zend MM 希望通过cache尽量做到, 一次定位就能查找分配.

  而一个不容易看懂的点是free_buckets的申明:

  Q: 为什么free_buckets数组的长度是ZEND_MM_NUMBER_BUCKET个?

  A: 这是因为, PHP在这处使用了一个技巧, 用一个定长的数组来存储ZEND_MM_NUMBER_BUCKET个zend_mm_free_block, 如上图中红色框所示. 对于一个没有被使用的free_buckets的元素, 唯一有用的数据结构就是next_free_block和prev_free_block, 所以, 为了节省内存, PHP并没有分配ZEND_MM_NUMBER_BUCKET * sizeof(zend_mm_free_block)大小的内存, 而只是用了ZEND_MM_NUMBER_BUCKET * (sizeof(*next_free_block) + sizeof(*prev_free_block))大小的内存..

  我们来看ZEND_MM_SMALL_FREE_BUCKET宏的定义:

 

  #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \

  (zend_mm_free_block*) ((char*)&heap->free_buckets[index * 2] + \

  sizeof(zend_mm_free_block*) * 2 - \

  sizeof(zend_mm_small_free_block))

 

  之后, Zend MM 保证只会使用prev和next俩个指针, 所以不会造成内存读错..

  那么, 第二个不容易看懂的点, 就是PHP对large_free_buckets的管理, 先介绍分配(TIPI项目组对此部分的描述有些含糊不清):

 

  static zend_mm_free_block *zend_mm_search_large_block(zend_mm_heap *heap, size_t true_size)

 

  large_free_buckets可以说是一个建树和双向列表的结合:

  

 

  large_free_buckets使用一个宏来决定某个大小的内存, 落在什么index上:

 

  #define ZEND_MM_LARGE_BUCKET_INDEX(S) zend_mm_high_bit(S)

 

  zend_mm_high_bit获取true_size中最高位1的序号(zend_mm_high_bit), 对应的汇编指令是bsr(此处, TIPI项目错误的说明为: “这个hash函数用来计算size的位数,返回值为size二进码中1的个数-1″).

  也就是说, 每一个在large_free_buckets中的元素, 都保持着指向一个大小为在对应index处为1的size的内存块的指针. 诶, 有点绕口, 举个例子:

  比如对于large_free_buckets[2], 就只会保存, 大小在0b1000到0b1111大小的内存. 再比如: large_free_buckets[6], 就保存着大小为0b10000000到0b11111111大小的内存的指针.

  这样, 再分配内存的时候, Zend MM就可以快速定位到最可能适合的区域来查找. 提高性能.

  而, 每一个元素又同时是一个双向列表, 保持着同样size的内存块, 而左右孩子(child[0]和child[1])分别代表着键值0和1, 这个键值是指什么呢?

  我们来举个例子, 比如我向PHP申请一个true_size为0b11010大小的内存, 经过一番步骤以后, 没有找到合适的内存, PHP进入了zend_mm_search_large_block的逻辑来在large_free_buckets中寻找合适的内存:

  1. 首先, 计算true_size对应的index, 计算方法如之前描述的ZEND_MM_LARGE_BUCKET_INDEX

  2. 然后在一个位图结构中, 判断是否存在一个大于true_size的可用内存已经存在于large_free_buckets, 如果不存在就返回:

 

  size_t bitmap = heap->large_free_bitmap >> index;

  if (bitmap == 0) {

  return NULL;

  }

 

  3. 判断, free_buckets[index]是否存在可用的内存:

 

  if (UNEXPECTED((bitmap & 1) != 0))

 

  4. 如果存在, 则从free_buckets[index]开始, 寻找最合适的内存, 步骤如下:

  4.1. 从free_buckets[index]开始, 如果free_buckets[index]当前的内存大小和true_size相等, 则寻找结束, 成功返回.

  4.2. 查看true_size对应index后(true_size child[1]下面继续寻找, 如果free_buckets[index]->child[1]不存在, 则跳出. 如果true_size的当前最高位为0, 则在free_buckets[index]->child[0]下面继续寻找, 如果free_buckets[index]->child[0]不存在, 则在free_buckets[index]->child[1]下面寻找最小内存(因为此时可以保证, 在free_buckets[index]->child[1]下面的内存都是大于true_size的)

  4.3. 出发点变更为2中所述的child, 左移一位ture_size.

  5. 如果上述逻辑并没有找到合适的内存, 则寻找最小的”大块内存”:

 

  /* Search for smallest "large" free block */

  best_fit = p = heap->large_free_buckets[index + zend_mm_low_bit(bitmap)];

  while ((p = p->child[p->child[0] != NULL])) {

  if (ZEND_MM_FREE_BLOCK_SIZE(p)

  best_fit = p;

  }

  }

 

  注意上面的逻辑, (p = p->child[p->child[0] != NULL]), PHP在尽量寻找最小的内存.

  为什么说, large_free_buckets是个键树呢, 从上面的逻辑我们可以看出, PHP把一个size, 按照二进制的01做键, 把内存大小信息反应到了键树上, 方便了快速查找.

  另外, 还有一个rest_buckets, 这个结构是个双向列表, 用来保存一些PHP分配后剩下的内存, 避免无意义的把剩余内存插入free_buckets带来的性能问题(此处, TIPI项目错误的描述为: “这是一个只有两个元素的数组。 而我们常用的插入和查找操作是针对第一个元素,即heap->rest_buckets[0]“).



Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

ChatGPT now allows free users to generate images by using DALL-E 3 with a daily limit ChatGPT now allows free users to generate images by using DALL-E 3 with a daily limit Aug 09, 2024 pm 09:37 PM

DALL-E 3 was officially introduced in September of 2023 as a vastly improved model than its predecessor. It is considered one of the best AI image generators to date, capable of creating images with intricate detail. However, at launch, it was exclus

What file is index.html? What file is index.html? Feb 19, 2024 pm 01:36 PM

index.html represents the home page file of the web page and is the default page of the website. When a user visits a website, the index.html page is usually loaded first. HTML (HypertextMarkupLanguage) is a markup language used to create web pages, and index.html is also an HTML file. It contains the structure and content of a web page, as well as tags and elements used for formatting and layout. Here is an example index.html code: &lt

Use java's File.length() function to get the size of the file Use java's File.length() function to get the size of the file Jul 24, 2023 am 08:36 AM

Use Java's File.length() function to get the size of a file. File size is a very common requirement when dealing with file operations. Java provides a very convenient way to get the size of a file, that is, using the length() method of the File class. . This article will introduce how to use this method to get the size of a file and give corresponding code examples. First, we need to create a File object to represent the file we want to get the size of. Here is how to create a File object: Filef

PHP Implementation Framework: Zend Framework Getting Started Tutorial PHP Implementation Framework: Zend Framework Getting Started Tutorial Jun 19, 2023 am 08:09 AM

PHP implementation framework: ZendFramework introductory tutorial ZendFramework is an open source website framework developed by PHP and is currently maintained by ZendTechnologies. ZendFramework adopts the MVC design pattern and provides a series of reusable code libraries to serve the implementation of Web2.0 applications and Web Serve. ZendFramework is very popular and respected by PHP developers and has a wide range of

How to use ACL (Access Control List) for permission control in Zend Framework How to use ACL (Access Control List) for permission control in Zend Framework Jul 29, 2023 am 09:24 AM

How to use ACL (AccessControlList) for permission control in Zend Framework Introduction: In a web application, permission control is a crucial function. It ensures that users can only access the pages and features they are authorized to access and prevents unauthorized access. The Zend framework provides a convenient way to implement permission control, using the ACL (AccessControlList) component. This article will introduce how to use ACL in Zend Framework

What are the advanced uses of the free command in Linux? What are the advanced uses of the free command in Linux? Feb 20, 2024 am 09:18 AM

In Linux systems, the free command is an important system tool used to monitor system memory usage. It provides basic usage to view information such as total memory, used amount, and available amount. In addition, there are some advanced uses, such as displaying detailed memory information, unit conversion, and real-time monitoring of memory. Basic usage of the free command: The basic syntax of the free command is as follows: free [options] Here are some commonly used options: -h: Display the memory size in a human-readable manner. -b: Display memory size in bytes. -k: Display memory size in kilobytes. -m: Display memory size in megabytes. -g: Display memory size in gigabytes. Sample Code: Let’s go through the sample code

Deepin V23 RC2 arrives with tweaks galore and optimizations aplenty Deepin V23 RC2 arrives with tweaks galore and optimizations aplenty Jun 28, 2024 am 07:45 AM

The AI-enabled Deepin Linux distro has just received its latest update, dubbed V23 RC2. This version of Deepin comes with a number of package updates and new features. But it's not all about the features; the look and feel are the main spotlight of t

PHP source code running problem: index error solution PHP source code running problem: index error solution Mar 09, 2024 pm 09:24 PM

PHP source code running problem: Index error resolution requires specific code examples. PHP is a widely used server-side scripting language that is often used to develop dynamic websites and web applications. However, sometimes you will encounter various problems when running PHP source code, among which "index error" is a common situation. This article will introduce some common causes and solutions of index errors, and provide specific code examples to help readers better deal with such problems. Problem Description: When running a PHP program

See all articles