加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Perl 内部结构详解

发布时间:2020-12-16 00:17:04 所属栏目:大数据 来源:网络整理
导读:PerlGuts Illustrated 直接命令行的方法查看:perl -MDevel::Peek -e "$a = 123; Dump $a" 简单的例子用来查看变量内部结构: use?Devel::Peek;?? ?? $a??=?123;?? @a?=?1..10;?? %a?=?1..10;?? ?????????? Dump?$a;?? Dump?@a ;?? Dump?%a;?? 标量: SV?=

PerlGuts Illustrated


直接命令行的方法查看:perl -MDevel::Peek -e "$a = 123; Dump $a"

简单的例子用来查看变量内部结构:

  1. use?Devel::Peek;??
  2. ??
  3. $a??=?123;??
  4. @a?=?1..10;??
  5. %a?=?1..10;??
  6. ??????????
  7. Dump?$a;??
  8. Dump?@a ;??
  9. Dump?%a;??

标量:

  1. SV?=?IV(0x2410960)?at?0x2410964??
  2. ??REFCNT?=?1??
  3. ??FLAGS?=?(IOK,pIOK)??
  4. ??IV?=?123??

数组:

  1. SV?=?RV(0x3a7190)?at?0x3a7184??
  2. ??REFCNT?=?1??
  3. ??FLAGS?=?(TEMP,ROK)??
  4. ??RV?=?0x24109c4??
  5. ??SV?=?PVAV(0x3a80ac)?at?0x24109c4??
  6. ????REFCNT?=?2??
  7. ????FLAGS?=?()??
  8. ????ARRAY?=?0x24c1aec??
  9. ????FILL?=?9??
  10. ????MAX?=?9??
  11. ????ARYLEN?=?0x0??
  12. ????FLAGS?=?(REAL)??
  13. ????Elt?No.?0??
  14. ????SV?=?IV(0x24c0450)?at?0x24c0454??
  15. ??????REFCNT?=?1??
  16. ??????FLAGS?=?(IOK,pIOK)??
  17. ??????IV?=?1??
  18. ????Elt?No.?1??
  19. ????SV?=?IV(0x24c0420)?at?0x24c0424??
  20. ??????REFCNT?=?1??
  21. ??????FLAGS?=?(IOK,pIOK)??
  22. ??????IV?=?2??
  23. ????Elt?No.?2??
  24. ????SV?=?IV(0x24b7e40)?at?0x24b7e44??
  25. ??????REFCNT?=?1??
  26. ??????FLAGS?=?(IOK,pIOK)??
  27. ??????IV?=?3??
  28. ????Elt?No.?3??
  29. ????SV?=?IV(0x24b7e50)?at?0x24b7e54??
  30. ??????REFCNT?=?1??
  31. ??????FLAGS?=?(IOK,pIOK)??
  32. ??????IV?=?4??

Hash:

  1. SV?=?RV(0xe7190)?at?0xe7184??
  2. ??REFCNT?=?1??
  3. ??FLAGS?=?(TEMP,ROK)??
  4. ??RV?=?0x24aaa0c??
  5. ??SV?=?PVHV(0x2401c94)?at?0x24aaa0c??
  6. ????REFCNT?=?2??
  7. ????FLAGS?=?(SHAREKEYS)??
  8. ????ARRAY?=?0x24bd47c??(0:3,?1:5)??
  9. ????hash?quality?=?150.0%??
  10. ????KEYS?=?5??
  11. ????FILL?=?5??
  12. ????MAX?=?7??
  13. ????RITER?=?-1??
  14. ????EITER?=?0x0??
  15. ????Elt?"1"?HASH?=?0x806b80c9??
  16. ????SV?=?IV(0x24b7ca0)?at?0x24b7ca4??
  17. ??????REFCNT?=?1??
  18. ??????FLAGS?=?(IOK,pIOK)??
  19. ??????IV?=?2??
  20. ????Elt?"3"?HASH?=?0xa400c7f3??
  21. ????SV?=?IV(0x24b7c80)?at?0x24b7c84??
  22. ??????REFCNT?=?1??
  23. ??????FLAGS?=?(IOK,pIOK)??
  24. ??????IV?=?4??
  25. ????Elt?"7"?HASH?=?0xecc9d984??
  26. ????SV?=?IV(0x24b7c60)?at?0x24b7c64??
  27. ??????REFCNT?=?1??
  28. ??????FLAGS?=?(IOK,pIOK)??
  29. ??????IV?=?8??

首先看一下Perl data structure。Perl内部称为SV(scalar value),AV(array value),HV(hash value),此外IV代表integer,NV代表double,PV代表string,RV代表指针,指向另外的任意数据结构。


Perl内部的数据结构之间的关系很像OO,用C structure内存裁减的方式模拟C++的继承。各种结构之间的继承关系如下图所示,它们之间是IS-A(是一个)的关系。


正如图所见,Perl使用以SvNULL为虚拟基类的多重继承,所有的类型都是根据type(small number)来确定并标记,因此你可以获取一个object的数据类型并且执行相应的操作。


下边为类型type 的定义,相应的解释分析见随后的blog:

  1. typedef?enum?{??
  2. ????SVt_NULL,???/*?0?*/??
  3. ????SVt_IV,?????/*?1?*/??
  4. ????SVt_NV,?????/*?2?*/??
  5. ????SVt_RV,?????/*?3?*/??
  6. ????SVt_PV,?????/*?4?*/??
  7. ????SVt_PVIV,???/*?5?*/??
  8. ????SVt_PVNV,???/*?6?*/??
  9. ????SVt_PVMG,???/*?7?*/??
  10. ????SVt_PVBM,???/*?8?*/??
  11. ????SVt_PVLV,???/*?9?*/??
  12. ????SVt_PVAV,???/*?10?*/??
  13. ????SVt_PVHV,???/*?11?*/??
  14. ????SVt_PVCV,???/*?12?*/??
  15. ????SVt_PVGV,???/*?13?*/??
  16. ????SVt_PVFM,???/*?14?*/??
  17. ????SVt_PVIO,???/*?15?*/??
  18. ????SVt_LAST????/*?keep?last?in?enum.?used?to?size?arrays?*/??
  19. }?svtype;??

_SV_HEAD and struct sv

下面来看一下最简单的类型struct sv,代表了SV,GV,CV,AV,HV,IO的通用结构。如下图所示:

第一个字段Any可以指向任意结构,除了RV,所有的其他类型都是由Any指向的附加数据来实现。
第二个字段REFCNT表明了有多少pointers引用了这个object。初始置为1,当有pointers指向它或者被销毁的时候,这个值需要相应的加1或者减1,当值为0的时候,内存释放。
第三个字段包含了FLAGS & TYPE,是一个32 bit unsigned int。如下图:

常见的flags见下边具体示例。


  1. C:&;perl?-MDevel::Peek?-e?"Dump?$a"??
  2. SV?=?NULL(0x0)?at?0x182a9fc??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?()??
  5. ??
  6. C:&;perl?-MDevel::Peek?-e?"Dump?$a"??
  7. SV?=?RV(0x299158)?at?0x29914c??
  8. ??REFCNT?=?1??
  9. ??FLAGS?=?(TEMP,ROK)??
  10. ??RV?=?0x182a9fc??
  11. ??SV?=?NULL(0x0)?at?0x182a9fc??
  12. ????REFCNT?=?2??
  13. ????FLAGS?=?()??


SvIV and SvNV

整数和小树,结构如图所示:

  1. C:&;perl?-MDevel::Peek?-e?"$a?=?123;?Dump?$a"??
  2. SV?=?IV(0x182aa20)?at?0x182aa24??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(IOK,pIOK)??
  5. ??IV?=?123??
  6. ??
  7. C:&;perl?-MDevel::Peek?-e?"$a?=?123.9;?Dump?$a"??
  8. SV?=?NV(0x184882c)?at?0x182aa2c??
  9. ??REFCNT?=?1??
  10. ??FLAGS?=?(NOK,pNOK)??
  11. ??NV?=?123.9??

SvPV

字符串,结构如图所示:


除了SV以外,额外的结构xpv被分配,它包含三部分:

PVX 指向实际的字符串。
CUR 标记字符串的长度,PVX+CUR 处的字符应该为'',标记字符串的结束。
LEN 标记内存分配给char * 的长度,以4为增量。

POK标记表示PVX所指向的内存包含有效字符串,否则所包含的字符串无效。

  1. C:&;perl?-MDevel::Peek?-e?"$a?=?'t';?Dump?$a"??
  2. SV?=?PV(0x296fec)?at?0x182aa24??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(POK,pPOK)??
  5. ??PV?=?0x182472c?"t"??
  6. ??CUR?=?1??
  7. ??LEN?=?4??
  8. ??
  9. C:&;perl?-MDevel::Peek?-e?"$a?=?'test';?Dump?$a"??
  10. SV?=?PV(0x296fec)?at?0x182aa2c??
  11. ??REFCNT?=?1??
  12. ??FLAGS?=?(POK,pPOK)??
  13. ??PV?=?0x182466c?"test"??
  14. ??CUR?=?4??
  15. ??LEN?=?8?(随着长度增加,以4为增量)??
  16. ??
  17. C:&;perl?-MDevel::Peek?-e?"$a?=?'test';?$a?=?undef;?Dump?$a"??
  18. SV?=?PV(0x296ffc)?at?0x182aa34??
  19. ??REFCNT?=?1??
  20. ??FLAGS?=?()??(包含字符串,但是无效)??
  21. ??PV?=?0x1824674?"test"??
  22. ??CUR?=?4??
  23. ??LEN?=?8??

SvOOK

为了提高移除字符串开头字符的速度,使用了OOK标记,IVX存储着偏移量,结构如图所示:


  1. C:&;perl?-MDevel::Peek?-e?"$a?=?'xtesting';?$a=~s/.//;?Dump?$a"??
  2. SV?=?PVIV(0x182005c)?at?0x182aa4c??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(POK,OOK,pPOK)??
  5. ??IV?=?1??(OFFSET)??
  6. ??PV?=?0x182467d?(?"x"?.?)?"testing"??
  7. ??CUR?=?7??
  8. ??LEN?=?11??

SvPVIV and SvPVNV

类似字符串,但是PVIV储存了额外的整数或者小数信息,可以根据flag直接进行数学运算,结构如图所示:

  1. C:&;perl?-MDevel::Peek?-e?"$a?=?'123.0';?0+$a;?Dump?$a"??
  2. SV?=?PVNV(0x29838c)?at?0x182aa34??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(IOK,NOK,POK,pIOK,pNOK,pPOK)??
  5. ??IV?=?123??
  6. ??NV?=?123??
  7. ??PV?=?0x1824674?"123.0"??
  8. ??CUR?=?5??
  9. ??LEN?=?8??
  10. ??
  11. C:&;perl?-MDevel::Peek?-e?"$a?=?'123testing';?0+$a;?Dump?$a"??
  12. SV?=?PVNV(0x298394)?at?0x182aa34??
  13. ??REFCNT?=?1??
  14. ??FLAGS?=?(POK,pPOK)??
  15. ??IV?=?123??
  16. ??NV?=?123??
  17. ??PV?=?0x1824674?"123testing"??
  18. ??CUR?=?10??
  19. ??LEN?=?12??

SvRV

类似指针,指向任意其他结构,结构如图所示:

  1. C:&;perl?-MDevel::Peek?-e?"$a?=?'123testing';?$b?=?$a?;?Dump?$b"??
  2. SV?=?RV(0x182ab68)?at?0x182ab5c??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(ROK)??
  5. ??RV?=?0x182aa4c??
  6. ??SV?=?PV(0x296ffc)?at?0x182aa4c??
  7. ????REFCNT?=?2??
  8. ????FLAGS?=?(POK,pPOK)??
  9. ????PV?=?0x182467c?"123testing"??
  10. ????CUR?=?10??
  11. ????LEN?=?12??

AV

数组,结构如图所示:

字段ALLOC 指向实际分配的SV 数组的开头地址。

字段ARRAY 指向数组本身的开头地址,由于数组的改变,这个地址比起实际分配的地址,可能会产生一定的偏移。

字段FILL 指向数组本身最后一个位置的偏移。

字段MAX 指向分配的SV 数组最后一个位置的偏移。

  1. C:&;perl?-MDevel::Peek?-e?"@a?=?1..2;?Dump?@a"??
  2. SV?=?RV(0x299120)?at?0x299114??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(TEMP,ROK)??
  5. ??RV?=?0x182a9cc??
  6. ??SV?=?PVAV(0x29a03c)?at?0x182a9cc??
  7. ????REFCNT?=?2??
  8. ????FLAGS?=?()??
  9. ????ARRAY?=?0x1852984??
  10. ????FILL?=?1??(数组最后一个元素index为1)??
  11. ????MAX?=?3???(分配的数组空间最大index为3,说明还有剩余空间来分配)??
  12. ????ARYLEN?=?0x0??
  13. ????FLAGS?=?(REAL)??
  14. ????Elt?No.?0??
  15. ????SV?=?IV(0x299220)?at?0x299224??
  16. ??????REFCNT?=?1??
  17. ??????FLAGS?=?(IOK,pIOK)??
  18. ??????IV?=?1??
  19. ????Elt?No.?1??
  20. ????SV?=?IV(0x299230)?at?0x299234??
  21. ??????REFCNT?=?1??
  22. ??????FLAGS?=?(IOK,pIOK)??
  23. ??????IV?=?2??

shift pop 操作可以通过调节ARRAY FILL MAX来完成。

  1. C:&;perl?-MDevel::Peek?-e?"@a?=?0..3;?Dump?@a ;?shift?@a ;?pop?@a ;?Dump?@a"??
  2. SV?=?RV(0x299130)?at?0x299124??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(TEMP,ROK)??
  5. ??RV?=?0x182aa14??
  6. ??SV?=?PVAV(0x29a04c)?at?0x182aa14??
  7. ????REFCNT?=?2??
  8. ????FLAGS?=?()??
  9. ????ARRAY?=?0x1824afc??
  10. ????FILL?=?3??
  11. ????MAX?=?3??
  12. ????ARYLEN?=?0x0??
  13. ????FLAGS?=?(REAL)??
  14. ????Elt?No.?0??
  15. ????SV?=?IV(0x299280)?at?0x299284??
  16. ??????REFCNT?=?1??
  17. ??????FLAGS?=?(IOK,pIOK)??
  18. ??????IV?=?0??
  19. ...??
  20. SV?=?RV(0x2991e0)?at?0x2991d4??
  21. ??REFCNT?=?1??
  22. ??FLAGS?=?(TEMP,ROK)??
  23. ??RV?=?0x182aa14??
  24. ??SV?=?PVAV(0x29a04c)?at?0x182aa14??
  25. ????REFCNT?=?2??
  26. ????FLAGS?=?()??
  27. ????ARRAY?=?0x1824b00?(offset=1)??
  28. ????ALLOC?=?0x1824afc??
  29. ????FILL?=?1??
  30. ????MAX?=?2??
  31. ????ARYLEN?=?0x0??
  32. ????FLAGS?=?(REAL)??
  33. ????Elt?No.?0??
  34. ????SV?=?IV(0x299200)?at?0x299204??
  35. ??????REFCNT?=?1??
  36. ??????FLAGS?=?(IOK,pIOK)??
  37. ??????IV?=?1??
  38. ????Elt?No.?1??
  39. ????SV?=?IV(0x182aa40)?at?0x182aa44??
  40. ??????REFCNT?=?1??
  41. ??????FLAGS?=?(IOK,pIOK)??
  42. ??????IV?=?2??
FLAGS REAL 表示所有内部的SV都需要有自己的引用计数,一般的AV 都是使用这个标记。

FLAGS REIFY 表示这个数组不是一个REAL 类型的,当这个数组发生改变的时候需要置为REAL,默认参数@_ 都是使用REIFY 标记。

HV

hash table是最复杂的数据结构,HV使用HE struct表示key/value结构,使用HEK表示key。

GvSTASH 当这个hash表示一个命名空间(模块),STASH指向Perl 语法树的一个节点,用来实现reset。(略过,未搞明白)

ARRAY 数组用于分配储存hash值,它的大小必须是2的n次方,当hash为空情况下,ARRAY为NULL。定位hash值在ARRAY中的位置只使用hash code的最后几位,ARRAY[HASH & MAX],稍后用一个例子说明。

FILL 表示ARRAY数组中有多少个不为NULL的节点。多个hash code可能共享ARRAY数组的一个节点,如上图所示。

MAX 表示ARRAY数组分配的空间减1,最小值为7,即使hash为空。

HE 包含三个指针,分别指向下一个节点,key和value。

HEK 包含hash code,key长度和key值。

RITER,EITER 这两个字段用来实现遍历hash 元素,RITER指向ARRAY的index,EITER指向HE的指针。当循环的时候,查找EITER->next值,为空的情况下RITER增1,直到ARRAY[RITER]不为空。初始情况RITER为-1,EITER 为空。

  1. C:&;perl?-MDevel::Peek?-e?"%a=0..5000;?Dump?%a"??
  2. SV?=?RV(0x299120)?at?0x299114??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(TEMP,ROK)??
  5. ??RV?=?0x182a9cc??
  6. ??SV?=?PVHV(0x29e7bc)?at?0x182a9cc??
  7. ????REFCNT?=?2??
  8. ????FLAGS?=?(SHAREKEYS)??
  9. ????ARRAY?=?0x18d12c4??(0:2236,?1:1341,?2:417,?3:85,?4:14,?5:3)??
  10. ????????(ARRAY中有2236个位置未占用,??
  11. ?????????有1341个位置包含1个元素,??
  12. ?????????有417个位置包含2个元素,??
  13. ?????????有85个位置包含3个元素,??
  14. ?????????有14个位置包含4个元素,??
  15. ?????????有3个位置包含5个元素,??
  16. ?????????1341+417+85+14+3=1860,正好是FILL的值??
  17. ????????)??
  18. ????hash?quality?=?98.9%??
  19. ????KEYS?=?2501?(hash包含的元素个数)??
  20. ????FILL?=?1860?(hash?code占用多少ARRAY位置,说明有多个值占用一个坑)??
  21. ????MAX?=?4095??(ARRAY分配了4096)??
  22. ????RITER?=?-1??
  23. ????EITER?=?0x0??
  24. ????Elt?"1648"?HASH?=?0x2bb13004??
  25. ????SV?=?IV(0x185a840)?at?0x185a844??
  26. ??????REFCNT?=?1??
  27. ??????FLAGS?=?(IOK,pIOK)??
  28. ??????IV?=?1649??
  29. ????Elt?"3596"?HASH?=?0x4b03006??
  30. ????SV?=?IV(0x18a4e38)?at?0x18a4e3c??
  31. ??????REFCNT?=?1??
  32. ??????FLAGS?=?(IOK,pIOK)??
  33. ??????IV?=?3597??
  34. ????Elt?"3074"?HASH?=?0x1256006??
  35. ????SV?=?IV(0x18beff0)?at?0x18beff4??
  36. ??????REFCNT?=?1??
  37. ??????FLAGS?=?(IOK,pIOK)??
  38. ??????IV?=?3075??
下边用一个例子说明RITER,EITER的变化过程。

取上边3个元素的hash code并与MAX 4095做& 运算,求得前三个元素在数组ARRAY中位置为4 6 6。

  1. printf?"%dn",??0x2bb13004?&?4095;??
  2. printf?"%dn",??0x4b03006?&?4095;??
  3. printf?"%dn",??0x1256006?&?4095;??
  4. ??
  5. output:??
  6. 4??
  7. 6??
  8. 6??
依次取hash 值并观察RITER,EITER的变化。

  1. use?Devel::Peek;??
  2. ??
  3. %a?=?0..5000;??
  4. #~?Dump?%a;??
  5. ??
  6. $i?=?0;??
  7. while(?my($a,$b)?=each?%a){??
  8. ????last?if?$i++?>?4;??
  9. ????print?"$a?$bn";??
  10. ????Dump?%a;??
  11. }??
值输出,同上边相同:

  1. 1648?1649??
  2. 3596?3597??
  3. 3074?3075??
  4. 2266?2267??
  5. 1178?1179??
RITER EITER在循环过程中ARRAY位置4 6 6与预计相同。

  1. SV?=?RV(0x298f98)?at?0x298f8c??
  2. ??REFCNT?=?1??
  3. ??FLAGS?=?(TEMP,ROK)??
  4. ??RV?=?0x182a8cc??
  5. ??SV?=?PVHV(0x29e59c)?at?0x182a8cc??
  6. ????REFCNT?=?2??
  7. ????FLAGS?=?(OOK,SHAREKEYS)??
  8. ????ARRAY?=?0x18d1164??(0:2236,?5:3)??
  9. ????hash?quality?=?98.9%??
  10. ????KEYS?=?2501??
  11. ????FILL?=?1860??
  12. ????MAX?=?4095??
  13. ????RITER?=?4??
  14. ????EITER?=?0x18a3c50??
  15. SV?=?RV(0x298f98)?at?0x298f8c??
  16. ??REFCNT?=?1??
  17. ??FLAGS?=?(TEMP,?5:3)??
  18. ????hash?quality?=?98.9%??
  19. ????KEYS?=?2501??
  20. ????FILL?=?1860??
  21. ????MAX?=?4095??
  22. ????RITER?=?6??
  23. ????EITER?=?0x18c3f48??
  24. SV?=?RV(0x298f98)?at?0x298f8c??
  25. ??REFCNT?=?1??
  26. ??FLAGS?=?(TEMP,?5:3)??
  27. ????hash?quality?=?98.9%??
  28. ????KEYS?=?2501??
  29. ????FILL?=?1860??
  30. ????MAX?=?4095??
  31. ????RITER?=?6??
  32. ????EITER?=?0x18ba91c??
  33. SV?=?RV(0x298f98)?at?0x298f8c??
  34. ??REFCNT?=?1??
  35. ??FLAGS?=?(TEMP,?5:3)??
  36. ????hash?quality?=?98.9%??
  37. ????KEYS?=?2501??
  38. ????FILL?=?1860??
  39. ????MAX?=?4095??
  40. ????RITER?=?9??
  41. ????EITER?=?0x18b1c4c??
  42. SV?=?RV(0x298f98)?at?0x298f8c??
  43. ??REFCNT?=?1??
  44. ??FLAGS?=?(TEMP,?5:3)??
  45. ????hash?quality?=?98.9%??
  46. ????KEYS?=?2501??
  47. ????FILL?=?1860??
  48. ????MAX?=?4095??
  49. ????RITER?=?11??
  50. ????EITER?=?0x1899dcc??

GV

GV "Global Value" 或者“符号表”,存储着变量或者函数的指针GP,由GP中slot 相关的指示来决定是否存在对应这个变量相应的类型。如图所示:

GP可以在多个GV中共享,试运行下例查看结果。

  1. D:perl?-MDevel::Peek?-e?"*test=*Dump;?Dump?*Dump;?Dump?*test"??
  2. SV?=?PVGV(0x285cda4)?at?0x286c0dc??
  3. ??REFCNT?=?5??
  4. ??FLAGS?=?(PADTMP,MULTI,ASSUMECV,IN_PAD,IMPORT(?CV?))??
  5. ??NAME?=?"Dump"??
  6. ??NAMELEN?=?4??
  7. ??GvSTASH?=?0x3a8fd4????"main"??
  8. ??GP?=?0x2864ffc??
  9. ????SV?=?0x0??
  10. ????REFCNT?=?2??
  11. ????IO?=?0x0??
  12. ????FORM?=?0x0????
  13. ????AV?=?0x0??
  14. ????HV?=?0x0??
  15. ????CV?=?0x2883874??
  16. ????CVGEN?=?0x0??
  17. ????LINE?=?67??
  18. ????FILE?=?"D:/Perl/lib/Exporter.pm"??
  19. ????FLAGS?=?0x8e??
  20. ????EGV?=?0x286c0dc?"Dump"??
  21. SV?=?PVGV(0x285cf04)?at?0x285a85c??
  22. ??REFCNT?=?3??
  23. ??FLAGS?=?(MULTI,IN_PAD)??
  24. ??NAME?=?"test"??
  25. ??NAMELEN?=?4??
  26. ??GvSTASH?=?0x3a8fd4????"main"??
  27. ??GP?=?0x2864ffc??
  28. ????SV?=?0x0??
  29. ????REFCNT?=?2??
  30. ????IO?=?0x0??
  31. ????FORM?=?0x0????
  32. ????AV?=?0x0??
  33. ????HV?=?0x0??
  34. ????CV?=?0x2883874??
  35. ????CVGEN?=?0x0??
  36. ????LINE?=?67??
  37. ????FILE?=?"D:/Perl/lib/Exporter.pm"??
  38. ????FLAGS?=?0xa??
  39. ????EGV?=?0x286c0dc?"Dump"??
REFCNT 引用数量,上边例子可以观察到。
EGV (effective gv) 表示创建这个GP的GV地址。
LINE 文件中行数。
FILE_HEK 在哪个文件中创建这个GV。

对应变量的GV可以用*var 来表示,字段GvSTASH 表示字段所在的命名空间,默认有一个main 命名空间。所有存储于GV中的类型都是全局的。

  1. D:perl?-MDevel::Peek?-e?"$a?=?123;?Dump?*a"??
  2. SV?=?PVGV(0x285ced4)?at?0x285a82c??
  3. ??REFCNT?=?3??
  4. ??FLAGS?=?(MULTI,IN_PAD)??
  5. ??NAME?=?"a"??
  6. ??NAMELEN?=?1??
  7. ??GvSTASH?=?0x3a8f9c????"main"??
  8. ??GP?=?0x286438c??
  9. ????SV?=?0x285a83c??
  10. ????REFCNT?=?1??
  11. ????IO?=?0x0??
  12. ????FORM?=?0x0????
  13. ????AV?=?0x0??
  14. ????HV?=?0x0??
  15. ????CV?=?0x0??
  16. ????CVGEN?=?0x0??
  17. ????LINE?=?1??
  18. ????FILE?=?"-e"??
  19. ????FLAGS?=?0xa??
  20. ????EGV?=?0x285a82c?"a"??

如果是从其它模块中引入的,则是通过Export引入main命名空间,实际指向的还是原始模块中的GV,看以下两个例子,函数Dump CV相同。

  1. D:Tmp>perl?-MDevel::Peek?-e?"Dump?*Devel::Peek::Dump"??
  2. SV?=?PVGV(0x285c894)?at?0x286c714??
  3. ??REFCNT?=?3??
  4. ??FLAGS?=?(MULTI,IN_PAD)??
  5. ??NAME?=?"Dump"??
  6. ??NAMELEN?=?4??
  7. ??GvSTASH?=?0x285aa0c???"Devel::Peek"??
  8. ??GP?=?0x2874484??
  9. ????SV?=?0x0??
  10. ????REFCNT?=?1??
  11. ????IO?=?0x0??
  12. ????FORM?=?0x0????
  13. ????AV?=?0x0??
  14. ????HV?=?0x0??
  15. ????CV?=?0x2883854??
  16. ????CVGEN?=?0x0??
  17. ????LINE?=?44??
  18. ????FILE?=?"D:/Perl/lib/Devel/Peek.pm"??
  19. ????FLAGS?=?0xa??
  20. ????EGV?=?0x286c714?"Dump"??
  21. ??
  22. D:Tmp>perl?-MDevel::Peek?-e?"Dump?*Dump"??
  23. SV?=?PVGV(0x285cd8c)?at?0x286c0f4??
  24. ??REFCNT?=?3??
  25. ??FLAGS?=?(PADTMP,IMPORT(?CV?))??
  26. ??NAME?=?"Dump"??
  27. ??NAMELEN?=?4??
  28. ??GvSTASH?=?0x3a8fc4????"main"??
  29. ??GP?=?0x2864fe4??
  30. ????SV?=?0x0??
  31. ????REFCNT?=?1??
  32. ????IO?=?0x0??
  33. ????FORM?=?0x0????
  34. ????AV?=?0x0??
  35. ????HV?=?0x0??
  36. ????CV?=?0x2883854??
  37. ????CVGEN?=?0x0??
  38. ????LINE?=?67??
  39. ????FILE?=?"D:/Perl/lib/Exporter.pm"??
  40. ????FLAGS?=?0x8e??
  41. ????EGV?=?0x286c0f4?"Dump"??

Stashes

GVs 同Stashes 共同作用实现了Perl 的命名空间,Stash 实际是HV,所有内容都指向GV。命名空间root 是defstash,指向main Stash。一个多层次模块,每一层都有一个相应的Stash。如下所示整体命名空间结构:



示例察看main 空间的内容,*:: 等同于*main::

  1. D:Tmp>perl?-MDevel::Peek?-e?"Dump?*::"??
  2. SV?=?PVGV(0x2851fdc)?at?0x3a8fe4??
  3. ??REFCNT?=?2??
  4. ??FLAGS?=?(READONLY,IN_PAD)??
  5. ??NAME?=?"main::"??
  6. ??NAMELEN?=?6??
  7. ??GvSTASH?=?0x3a8fc4????"main"??
  8. ??GP?=?0x2852fd4??
  9. ????SV?=?0x0??
  10. ????REFCNT?=?1??
  11. ????IO?=?0x0??
  12. ????FORM?=?0x0????
  13. ????AV?=?0x0??
  14. ????HV?=?0x3a8fc4??
  15. ????CV?=?0x0??
  16. ????CVGEN?=?0x0??
  17. ????LINE?=?0??
  18. ????FILE?=?""??
  19. ????FLAGS?=?0xa??
  20. ????EGV?=?0x3a8fe4??"main::"??

查看main 中HV 包含的内容,节选了部分来演示:

  1. D:Tmp>perl?-MDevel::Peek?-e?"Dump?%::,1000"??
  2. SV?=?RV(0x3a90e0)?at?0x3a90d4??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(TEMP,ROK)??
  5. ??RV?=?0x3a8fc4??
  6. ??SV?=?PVHV(0x3ae2dc)?at?0x3a8fc4??
  7. ????REFCNT?=?3??
  8. ????FLAGS?=?(OOK,SHAREKEYS)??
  9. ????ARRAY?=?0x287b234??(0:74,?1:44,?2:8,?3:2)??
  10. ????hash?quality?=?105.9%??
  11. ????KEYS?=?66??
  12. ????FILL?=?54??
  13. ????MAX?=?127??
  14. ????RITER?=?-1??
  15. ????EITER?=?0x0??
  16. ????NAME?=?"main"??
  17. ????BACKREFS?=?0x3a8ff4??
  18. ??????
  19. ????......??
  20. ??????
  21. ????Elt?"Devel::"?HASH?=?0xfa558e0e??
  22. ????SV?=?PVGV(0x285c314)?at?0x285a9cc??
  23. ??????REFCNT?=?1??
  24. ??????FLAGS?=?(MULTI)??
  25. ??????NAME?=?"Devel::"??
  26. ??????NAMELEN?=?7??
  27. ??????GvSTASH?=?0x3a8fc4????"main"??
  28. ??????GP?=?0x28654ac??
  29. ????????SV?=?0x0??
  30. ????????REFCNT?=?1??
  31. ????????IO?=?0x0??
  32. ????????FORM?=?0x0????
  33. ????????AV?=?0x0??
  34. ????????HV?=?0x285a9dc??
  35. ????????CV?=?0x0??
  36. ????????CVGEN?=?0x0??
  37. ????????LINE?=?4??
  38. ????????FILE?=?"D:/Perl/lib/Devel/Peek.pm"??
  39. ????????FLAGS?=?0x2??
  40. ????????EGV?=?0x285a9cc?"Devel::"??
  41. ????......??
  42. ????Elt?"Dump"?HASH?=?0xbbea0f76??
  43. ????SV?=?PVGV(0x285cd94)?at?0x286c0f4??
  44. ??????REFCNT?=?2??
  45. ??????FLAGS?=?(PADTMP,IMPORT(?CV?))??
  46. ??????NAME?=?"Dump"??
  47. ??????NAMELEN?=?4??
  48. ??????GvSTASH?=?0x3a8fc4????"main"??
  49. ??????GP?=?0x2864fe4??
  50. ????????SV?=?0x0??
  51. ????????REFCNT?=?1??
  52. ????????IO?=?0x0??
  53. ????????FORM?=?0x0????
  54. ????????AV?=?0x0??
  55. ????????HV?=?0x0??
  56. ????????CV?=?0x2883854??
  57. ????????CVGEN?=?0x0??
  58. ????????LINE?=?67??
  59. ????????FILE?=?"D:/Perl/lib/Exporter.pm"??
  60. ????????FLAGS?=?0x8e??
  61. ????????EGV?=?0x286c0f4?"Dump"??
  62. ????......??
  63. ????Elt?"main::"?HASH?=?0x40383f65??
  64. ????SV?=?PVGV(0x2851fdc)?at?0x3a8fe4??
  65. ??????REFCNT?=?2??
  66. ??????FLAGS?=?(READONLY,IN_PAD)??
  67. ??????NAME?=?"main::"??
  68. ??????NAMELEN?=?6??
  69. ??????GvSTASH?=?0x3a8fc4????"main"??
  70. ??????GP?=?0x2852fd4??
  71. ????????SV?=?0x0??
  72. ????????REFCNT?=?1??
  73. ????????IO?=?0x0??
  74. ????????FORM?=?0x0????
  75. ????????AV?=?0x0??
  76. ????????HV?=?0x3a8fc4??
  77. ????????CV?=?0x0??
  78. ????????CVGEN?=?0x0??
  79. ????????LINE?=?0??
  80. ????????FILE?=?""??
  81. ????????FLAGS?=?0xa??
  82. ????????EGV?=?0x3a8fe4??"main::"??
  83. ????Elt?"ENV"?HASH?=?0x62ffe0d6??
  84. ????SV?=?PVGV(0x285c2b4)?at?0x285a55c??
  85. ??????REFCNT?=?1??
  86. ??????FLAGS?=?(MULTI)??
  87. ??????NAME?=?"ENV"??
  88. ??????NAMELEN?=?3??
  89. ??????GvSTASH?=?0x3a8fc4????"main"??
  90. ??????GP?=?0x285e184??
  91. ????????SV?=?0x0??
  92. ????????REFCNT?=?1??
  93. ????????IO?=?0x0??
  94. ????????FORM?=?0x0????
  95. ????????AV?=?0x0??
  96. ????????HV?=?0x285a56c??
  97. ????????CV?=?0x0??
  98. ????????CVGEN?=?0x0??
  99. ????????LINE?=?0??
  100. ????????FILE?=?"-e"??
  101. ????????FLAGS?=?0x2??
  102. ????????EGV?=?0x285a55c?"ENV"??

查看多层次模块中的内容:

  1. D:Tmp>perl?-MDevel::Peek?-e?"Dump?%Devel::,ROK)??
  2. ??RV?=?0x285a9dc??
  3. ??SV?=?PVHV(0x3ae57c)?at?0x285a9dc??
  4. ????REFCNT?=?2??
  5. ????FLAGS?=?(OOK,SHAREKEYS)??
  6. ????ARRAY?=?0x2865534??(0:7,?1:1)??
  7. ????hash?quality?=?100.0%??
  8. ????KEYS?=?1??
  9. ????FILL?=?1??
  10. ????MAX?=?7??
  11. ????RITER?=?-1??
  12. ????EITER?=?0x0??
  13. ????NAME?=?"Devel"??
  14. ????BACKREFS?=?0x285a9fc??
  15. ????SV?=?PVAV(0x3aa32c)?at?0x285a9fc??
  16. ??????REFCNT?=?2??
  17. ??????FLAGS?=?()??
  18. ??????ARRAY?=?0x286561c??
  19. ??????FILL?=?0??
  20. ??????MAX?=?3??
  21. ??????ARYLEN?=?0x0??
  22. ??????FLAGS?=?()??
  23. ??????Elt?No.?0??
  24. ??????SV?=?PVGV(0x285c334)?at?0x285a9ec??
  25. ????????REFCNT?=?1??
  26. ????????FLAGS?=?(MULTI)??
  27. ????????NAME?=?"Peek::"??
  28. ????????NAMELEN?=?6??
  29. ????????GvSTASH?=?0x285a9dc?"Devel"??
  30. ????????GP?=?0x28655dc??
  31. ??????????SV?=?0x0??
  32. ??????????REFCNT?=?1??
  33. ??????????IO?=?0x0??
  34. ??????????FORM?=?0x0????
  35. ??????????AV?=?0x0??
  36. ??????????HV?=?0x285aa0c??
  37. ??????????CV?=?0x0??
  38. ??????????CVGEN?=?0x0??
  39. ??????????LINE?=?4??
  40. ??????????FILE?=?"D:/Perl/lib/Devel/Peek.pm"??
  41. ??????????FLAGS?=?0x2??
  42. ??????????EGV?=?0x285a9ec???"Peek::"??
  43. ????Elt?"Peek::"?HASH?=?0xf40ca9c??
  44. ????SV?=?PVGV(0x285c334)?at?0x285a9ec??
  45. ??????REFCNT?=?1??
  46. ??????FLAGS?=?(MULTI)??
  47. ??????NAME?=?"Peek::"??
  48. ??????NAMELEN?=?6??
  49. ??????GvSTASH?=?0x285a9dc???"Devel"??
  50. ??????GP?=?0x28655dc??
  51. ????????SV?=?0x0??
  52. ????????REFCNT?=?1??
  53. ????????IO?=?0x0??
  54. ????????FORM?=?0x0????
  55. ????????AV?=?0x0??
  56. ????????HV?=?0x285aa0c??
  57. ????????CV?=?0x0??
  58. ????????CVGEN?=?0x0??
  59. ????????LINE?=?4??
  60. ????????FILE?=?"D:/Perl/lib/Devel/Peek.pm"??
  61. ????????FLAGS?=?0x2??
  62. ????????EGV?=?0x285a9ec?"Peek::"??

希望通过这一节都能对Perl的整体有一个了解,相信其他语言也有类似的概念结构来实现命名空间的引入。

CV

code value,函数的结构,如下图:

下边示例可以看到几个主要参数:

函数所在的Stash & GV。

函数的参数表和临时变量表PADLIST。

  1. D:Tmp>perl?-MDevel::Peek?-e?"sub?a{my?($a,$b,$t);?}?Dump?&;a"??
  2. SV?=?RV(0x3a90f0)?at?0x3a90e4??
  3. ??REFCNT?=?1??
  4. ??FLAGS?=?(TEMP,ROK)??
  5. ??RV?=?0x285a864??
  6. ??SV?=?PVCV(0x285923c)?at?0x285a864??
  7. ????REFCNT?=?2??
  8. ????FLAGS?=?()??
  9. ????COMP_STASH?=?0x3a8fd4???"main"??
  10. ????START?=?0x2885fa8?===>?0??
  11. ????ROOT?=?0x2885f64??
  12. ????GVGV::GV?=?0x285abd4????"main"?::?"a"??
  13. ????FILE?=?"-e"??
  14. ????DEPTH?=?0??
  15. ????FLAGS?=?0x0??
  16. ????OUTSIDE_SEQ?=?96??
  17. ????PADLIST?=?0x285a874??
  18. ????PADNAME?=?0x285a8a4(0x2865424)?PAD?=?0x285a974(0x288292c)??
  19. ???????1.?0x285a8c4<1>?(96,97)?"$a"??
  20. ???????2.?0x285a894<1>?(96,97)?"$b"??
  21. ???????3.?0x285a904<1>?(96,97)?"$t"??
  22. ????OUTSIDE?=?0x3a9274?(MAIN)??


PAD

PAD是一个列表,为每个函数存储局部变量。第0个slot 存储参数名字,运行时产生新的AV存储实际参数,DEPTH也加深,递归函数观察效果明显。

  1. use?Devel::Peek;??
  2. use?Data::Dumper;??
  3. ??
  4. sub?test{??
  5. ????my?($a,$b)?=?@_;??
  6. ????Dump?&;test;??
  7. ????test(++$a,--$b)?if?$b>0;??
  8. }??
  9. ??
  10. Dump?&;test;??
  11. test(1,2);??
  12. ??
  13. ??
  14. 输出:??
  15. SV?=?RV(0x298f50)?at?0x298f44??
  16. ??REFCNT?=?1??
  17. ??FLAGS?=?(TEMP,ROK)??
  18. ??RV?=?0x182a834??
  19. ??SV?=?PVCV(0x1829024)?at?0x182a834??
  20. ????REFCNT?=?2??
  21. ????FLAGS?=?()??
  22. ????COMP_STASH?=?0x298e34???"main"??
  23. ????START?=?0x18ba94c?===>?0??
  24. ????ROOT?=?0x18ba4cc??
  25. ????GVGV::GV?=?0x184b34c????"main"?::?"test"??
  26. ????FILE?=?"tmp.pl"??
  27. ????DEPTH?=?0??
  28. ????FLAGS?=?0x0??
  29. ????OUTSIDE_SEQ?=?535??
  30. ????PADLIST?=?0x182a864??
  31. ????PADNAME?=?0x182a934(0x18c7c6c)?PAD?=?0x182a8c4(0x18c7be4)??
  32. ???????1.?0x182a854<1>?(535,536)?"$a"??
  33. ???????2.?0x182a884<1>?(535,536)?"$b"??
  34. ????OUTSIDE?=?0x299094?(MAIN)??
  35. SV?=?RV(0x298f50)?at?0x298f44??
  36. ??REFCNT?=?1??
  37. ??FLAGS?=?(TEMP,ROK)??
  38. ??RV?=?0x182a834??
  39. ??SV?=?PVCV(0x1829024)?at?0x182a834??
  40. ????REFCNT?=?4??
  41. ????FLAGS?=?()??
  42. ????COMP_STASH?=?0x298e34???"main"??
  43. ????START?=?0x18ba94c?===>?0??
  44. ????ROOT?=?0x18ba4cc??
  45. ????GVGV::GV?=?0x184b34c????"main"?::?"test"??
  46. ????FILE?=?"tmp.pl"??
  47. ????DEPTH?=?1??
  48. ????FLAGS?=?0x0??
  49. ????OUTSIDE_SEQ?=?535??
  50. ????PADLIST?=?0x182a864??
  51. ????PADNAME?=?0x182a934(0x18c7c6c)?PAD?=?0x182a8c4(0x18c7be4)??
  52. ???????1.?0x182a854<1>?(535,536)?"$b"??
  53. ????OUTSIDE?=?0x299094?(MAIN)??
  54. SV?=?RV(0x1899240)?at?0x1899234??
  55. ??REFCNT?=?1??
  56. ??FLAGS?=?(TEMP,ROK)??
  57. ??RV?=?0x182a834??
  58. ??SV?=?PVCV(0x1829024)?at?0x182a834??
  59. ????REFCNT?=?4??
  60. ????FLAGS?=?()??
  61. ????COMP_STASH?=?0x298e34???"main"??
  62. ????START?=?0x18ba94c?===>?0??
  63. ????ROOT?=?0x18ba4cc??
  64. ????GVGV::GV?=?0x184b34c????"main"?::?"test"??
  65. ????FILE?=?"tmp.pl"??
  66. ????DEPTH?=?2??
  67. ????FLAGS?=?0x0??
  68. ????OUTSIDE_SEQ?=?535??
  69. ????PADLIST?=?0x182a864??
  70. ????PADNAME?=?0x182a934(0x18c7c6c)?PAD?=?0x182a8c4(0x18c7be4)??
  71. ???????1.?0x182a854<1>?(535,536)?"$b"??
  72. ????OUTSIDE?=?0x299094?(MAIN)??
  73. SV?=?RV(0x1863a28)?at?0x1863a1c??
  74. ??REFCNT?=?1??
  75. ??FLAGS?=?(TEMP,ROK)??
  76. ??RV?=?0x182a834??
  77. ??SV?=?PVCV(0x1829024)?at?0x182a834??
  78. ????REFCNT?=?4??
  79. ????FLAGS?=?()??
  80. ????COMP_STASH?=?0x298e34???"main"??
  81. ????START?=?0x18ba94c?===>?0??
  82. ????ROOT?=?0x18ba4cc??
  83. ????GVGV::GV?=?0x184b34c????"main"?::?"test"??
  84. ????FILE?=?"tmp.pl"??
  85. ????DEPTH?=?3??
  86. ????FLAGS?=?0x0??
  87. ????OUTSIDE_SEQ?=?535??
  88. ????PADLIST?=?0x182a864??
  89. ????PADNAME?=?0x182a934(0x18c7c6c)?PAD?=?0x182a8c4(0x18c7be4)??
  90. ???????1.?0x182a854<1>?(535,536)?"$b"??
  91. ????OUTSIDE?=?0x299094?(MAIN)??

词法变量(my & our)会设置SVs_PADMY/SVs_PADOUR标记,目标设置SVs_PADTMP标记。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读