php原始碼02 -基本變數與記憶體管理機制
概述
這是原始碼php7系列的第二篇文章,主要介紹變數的機制和記憶體的管理,我相信學習原始碼是對程式碼整體提升的有效手段,話不多說,開始吧!
php7編譯安轉、新特性
變數實現
1. 解密zval
zval 底層結構:
struct_zval_struct {
zend_value value; //8個位元組
union u1; //4個位元組
union u2; //4個位元組
}
1
2
3
4
5
對於vue來說是一個聯合體,zval一共16個位元組,u1 4個位元組,u2四個位元組,value結構體如下:
typedef union _zend_value {
zend_long lval; /* long value */
double dval; /* double value */
zend_refcounted *counted;
zend_string *str;
zend_array *arr;
zend_object *obj;
zend_resource *res;
zend_reference *ref;
zend_ast_ref *ast;
zval *zv;
void *ptr;
zend_class_entry *ce;
zend_function *func;
struct {
uint32_t w1;
uint32_t w2;
} ww;
} zend_value;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
雖然PHP屬於弱型別語言,但是在底層實現中還是要區分型別的,因為型別裡有天然的長度,型別引勢記憶體的長度。
底層做了很多型別轉化的處理,讓我們不用關心php的型別和長度,這也是php開發高效的原因之一。
變數知識點:
value、u1、u2都是聯合體,在底層是要區分型別的
u2裡面有個重要的變數next,next會在陣列中解決衝突使用
2.寫時複製(Copy On Write)
struct _zend_string {
zend_refcounted_h gc;
zend_ulong h; /* hash value */
size_t len;
char val[1];
};
1
2
3
4
5
6
zend_refcounted_h 作用是string型別的引用計數的結構體,h是字串對應的hash值,它後面會用到陣列裡,len代表字串的長度,char是字串的值,因為C言語中字串遇到\0就會自動結束,二進位制是不安全的,所以php加上了長度。
$value1 = 'stark';
$value2 = $value1;
$value2 = 'zcc';
1
2
3
php的寫時複製是這樣發生的,如果把v a l u e 1 賦 值 給 value1賦值給value1賦值給value2,兩個變數指向的是同一個實體記憶體地址,存在硬碟上的某一個塊裡,也許地址是0x7fff5e01c00,當$value2賦值新的值時,zend_refcounted_h引用計數減一,zcc存入新的地址。可以看我之前的文章。
3.字串的引用型別
struct _zend_reference {
zend_refcounted_h gc;
zval val;
};
1
2
3
4
可以跟著程式碼執行一下,看看你心裡的預期和實際列印出的值是否一致
$a = 'hello';
$b = &$a;
var_dump($a,$b);
$b = 'stark';
var_dump($a,$b);
unset($b);
var_dump($a,$b);
1
2
3
4
5
6
7
8
9
執行結果:
[root@dd2065d03db8 code]# /usr/local/php7.1.0/bin/php refer.php
string(5) "hello"
string(5) "hello"
string(5) "stark"
string(5) "stark"
string(5) "stark"
NULL
1
2
3
4
5
6
7
原始碼中的陣列HashTable
struct _zend_array {
zend_refcounted_h gc;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar flags,
zend_uchar nApplyCount,
zend_uchar nIteratorsCount,
zend_uchar consistency)
} v;
uint32_t flags;
} u;
uint32_t nTableMask;
Bucket *arData;
uint32_t nNumUsed;
uint32_t nNumOfElements;
uint32_t nTableSize;
uint32_t nInternalPointer;
zend_long nNextFreeElement;
dtor_func_t pDestructor;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
nTableMask是計算陣列的索引值,*arData儲存陣列裡的key=>value的鍵值對,nNumUsed表示已經使用的空間,nNumOfElements真正的元素個數,nTableSize是arData的大小,nTableSize預設大小是8位元組,記憶體不夠每次擴容都x2,以此類推。
記憶體管理
在malloc申請記憶體時宣告瞭size大小,但是回收時沒有傳size,怎麼做到準確釋放size大小記憶體的呢?
void *ptr=malloc(size);
free(ptr);
1
2
php7記憶體介面
void *ptr=_emalloc(size);
_efree(ptr);
1
2
1.Small記憶體的管理
記憶體的基本概念:chunk、page、各種規格的記憶體。
chunk: 2MB 大小的記憶體
page :4KB大小的記憶體
#define ZEND_MM_CHUNK_SIZE (2 * 1024 * 1024) /* 2 MB */
#define ZEND_MM_PAGE_SIZE (4 * 1024) /* 4 KB */
#define ZEND_MM_PAGES (ZEND_MM_CHUNK_SIZE / ZEND_MM_PAGE_SIZE) /* 512 */
1
2
3
記憶體規格
記憶體預分配:使用mmap分配chunk
記憶體分類:
1.Small(30種規格) (size <= 3KB)
2.Large (3KB < size <= 2MB-4KB)
3.Huge(size > 2MB-4KB)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70010128/viewspace-2871664/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python記憶體管理機制-《原始碼解析》Python記憶體原始碼
- Python原始碼閱讀-記憶體管理機制(一)Python原始碼記憶體
- Python原始碼閱讀-記憶體管理機制(二)Python原始碼記憶體
- MySQL • 原始碼分析 • 記憶體分配機制MySql原始碼記憶體
- javaScript 記憶體管理機制JavaScript記憶體
- Java記憶體管理機制Java記憶體
- Qt 記憶體管理機制QT記憶體
- jvm記憶體管理機制JVM記憶體
- Windows記憶體機制解析(二)原始碼 (轉)Windows記憶體原始碼
- android記憶體管理機制與優化Android記憶體優化
- Qt 記憶體管理機制薦QT記憶體
- linux記憶體管理機制Linux記憶體
- 記憶體管理原始碼 (轉)記憶體原始碼
- 淺析java記憶體管理機制Java記憶體
- 記憶體管理機制的發展記憶體
- ARC記憶體管理機制詳解記憶體
- 【記憶體管理】頁面分配機制記憶體
- Android學習之 記憶體管理機制與應用記憶體優化Android記憶體優化
- 變數、作用域與記憶體變數記憶體
- Memcached記憶體管理原始碼分析記憶體原始碼
- PHP 垃圾回收與記憶體管理指引PHP記憶體
- iOS全域性變數與屬性的記憶體管理iOS變數記憶體
- C++動態記憶體管理與原始碼剖析C++記憶體原始碼
- php的變數引用與銷燬機制PHP變數
- 什麼是記憶體管理?其最主要作用?OC記憶體管理機制?記憶體
- JVM自動記憶體管理機制 二JVM記憶體
- 淺談Linux記憶體管理機制Linux記憶體
- AIX虛擬記憶體管理機制(轉)AI記憶體
- IBM的AIX記憶體管理機制IBMAI記憶體
- Android彈藥庫——記憶體管理機制與程式模型Android記憶體模型
- Java的記憶體管理機制之記憶體區域劃分Java記憶體
- Python如何管理記憶體?記憶體分配機制是什麼?Python記憶體
- Python記憶體管理:基本概念與技巧Python記憶體
- JavaScript 記憶體機制JavaScript記憶體
- 垃圾收集機制與記憶體分配策略記憶體
- 一文洞悉JVM記憶體管理機制JVM記憶體
- Objective-C中的記憶體管理機制Object記憶體
- 深度學習 Caffe 記憶體管理機制理解深度學習記憶體