Perl 内部结构详解 -- PerlGuts Illustrated (5 GV & Stash)

来源:互联网 发布:怎么关闭mac打开的图标 编辑:程序博客网 时间:2024/03/29 15:43

GV

GV "Global Value" 或者“符号表”,存储着变量或者函数的指针GP,由GP中slot 相关的指示来决定是否存在对应这个变量相应的类型。如图所示:
GP可以在多个GV中共享,试运行下例查看结果。
D:\perl -MDevel::Peek -e "*test=*Dump; Dump *Dump; Dump *test"SV = PVGV(0x285cda4) at 0x286c0dc  REFCNT = 5  FLAGS = (PADTMP,MULTI,ASSUMECV,IN_PAD,IMPORT( CV ))  NAME = "Dump"  NAMELEN = 4  GvSTASH = 0x3a8fd4"main"  GP = 0x2864ffc    SV = 0x0    REFCNT = 2    IO = 0x0    FORM = 0x0      AV = 0x0    HV = 0x0    CV = 0x2883874    CVGEN = 0x0    LINE = 67    FILE = "D:/Perl/lib/Exporter.pm"    FLAGS = 0x8e    EGV = 0x286c0dc"Dump"SV = PVGV(0x285cf04) at 0x285a85c  REFCNT = 3  FLAGS = (MULTI,IN_PAD)  NAME = "test"  NAMELEN = 4  GvSTASH = 0x3a8fd4"main"  GP = 0x2864ffc    SV = 0x0    REFCNT = 2    IO = 0x0    FORM = 0x0      AV = 0x0    HV = 0x0    CV = 0x2883874    CVGEN = 0x0    LINE = 67    FILE = "D:/Perl/lib/Exporter.pm"    FLAGS = 0xa    EGV = 0x286c0dc"Dump"
REFCNT 引用数量,上边例子可以观察到。
EGV (effective gv) 表示创建这个GP的GV地址。
LINE 文件中行数。
FILE_HEK 在哪个文件中创建这个GV。

对应变量的GV可以用*var 来表示,字段GvSTASH 表示字段所在的命名空间,默认有一个main 命名空间。所有存储于GV中的类型都是全局的。
D:\perl -MDevel::Peek -e "$a = 123; Dump *a"SV = PVGV(0x285ced4) at 0x285a82c  REFCNT = 3  FLAGS = (MULTI,IN_PAD)  NAME = "a"  NAMELEN = 1  GvSTASH = 0x3a8f9c"main"  GP = 0x286438c    SV = 0x285a83c    REFCNT = 1    IO = 0x0    FORM = 0x0      AV = 0x0    HV = 0x0    CV = 0x0    CVGEN = 0x0    LINE = 1    FILE = "-e"    FLAGS = 0xa    EGV = 0x285a82c"a"

如果是从其它模块中引入的,则是通过Export引入main命名空间,实际指向的还是原始模块中的GV,看以下两个例子,函数Dump CV相同。
D:\Tmp>perl -MDevel::Peek -e "Dump *Devel::Peek::Dump"SV = PVGV(0x285c894) at 0x286c714  REFCNT = 3  FLAGS = (MULTI,IN_PAD)  NAME = "Dump"  NAMELEN = 4  GvSTASH = 0x285aa0c"Devel::Peek"  GP = 0x2874484    SV = 0x0    REFCNT = 1    IO = 0x0    FORM = 0x0      AV = 0x0    HV = 0x0    CV = 0x2883854    CVGEN = 0x0    LINE = 44    FILE = "D:/Perl/lib/Devel/Peek.pm"    FLAGS = 0xa    EGV = 0x286c714"Dump"D:\Tmp>perl -MDevel::Peek -e "Dump *Dump"SV = PVGV(0x285cd8c) at 0x286c0f4  REFCNT = 3  FLAGS = (PADTMP,MULTI,ASSUMECV,IN_PAD,IMPORT( CV ))  NAME = "Dump"  NAMELEN = 4  GvSTASH = 0x3a8fc4"main"  GP = 0x2864fe4    SV = 0x0    REFCNT = 1    IO = 0x0    FORM = 0x0      AV = 0x0    HV = 0x0    CV = 0x2883854    CVGEN = 0x0    LINE = 67    FILE = "D:/Perl/lib/Exporter.pm"    FLAGS = 0x8e    EGV = 0x286c0f4"Dump"

Stashes

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


示例察看main 空间的内容,*:: 等同于*main::
D:\Tmp>perl -MDevel::Peek -e "Dump *::"SV = PVGV(0x2851fdc) at 0x3a8fe4  REFCNT = 2  FLAGS = (READONLY,MULTI,IN_PAD)  NAME = "main::"  NAMELEN = 6  GvSTASH = 0x3a8fc4"main"  GP = 0x2852fd4    SV = 0x0    REFCNT = 1    IO = 0x0    FORM = 0x0      AV = 0x0    HV = 0x3a8fc4    CV = 0x0    CVGEN = 0x0    LINE = 0    FILE = ""    FLAGS = 0xa    EGV = 0x3a8fe4"main::"

查看main 中HV 包含的内容,节选了部分来演示:
D:\Tmp>perl -MDevel::Peek -e "Dump \%::,1000"SV = RV(0x3a90e0) at 0x3a90d4  REFCNT = 1  FLAGS = (TEMP,ROK)  RV = 0x3a8fc4  SV = PVHV(0x3ae2dc) at 0x3a8fc4    REFCNT = 3    FLAGS = (OOK,SHAREKEYS)    ARRAY = 0x287b234  (0:74, 1:44, 2:8, 3:2)    hash quality = 105.9%    KEYS = 66    FILL = 54    MAX = 127    RITER = -1    EITER = 0x0    NAME = "main"    BACKREFS = 0x3a8ff4        ......        Elt "Devel::" HASH = 0xfa558e0e    SV = PVGV(0x285c314) at 0x285a9cc      REFCNT = 1      FLAGS = (MULTI)      NAME = "Devel::"      NAMELEN = 7      GvSTASH = 0x3a8fc4"main"      GP = 0x28654ac        SV = 0x0        REFCNT = 1        IO = 0x0        FORM = 0x0          AV = 0x0        HV = 0x285a9dc        CV = 0x0        CVGEN = 0x0        LINE = 4        FILE = "D:/Perl/lib/Devel/Peek.pm"        FLAGS = 0x2        EGV = 0x285a9cc"Devel::"    ......    Elt "Dump" HASH = 0xbbea0f76    SV = PVGV(0x285cd94) at 0x286c0f4      REFCNT = 2      FLAGS = (PADTMP,MULTI,ASSUMECV,IN_PAD,IMPORT( CV ))      NAME = "Dump"      NAMELEN = 4      GvSTASH = 0x3a8fc4"main"      GP = 0x2864fe4        SV = 0x0        REFCNT = 1        IO = 0x0        FORM = 0x0          AV = 0x0        HV = 0x0        CV = 0x2883854        CVGEN = 0x0        LINE = 67        FILE = "D:/Perl/lib/Exporter.pm"        FLAGS = 0x8e        EGV = 0x286c0f4"Dump"    ......    Elt "main::" HASH = 0x40383f65    SV = PVGV(0x2851fdc) at 0x3a8fe4      REFCNT = 2      FLAGS = (READONLY,MULTI,IN_PAD)      NAME = "main::"      NAMELEN = 6      GvSTASH = 0x3a8fc4"main"      GP = 0x2852fd4        SV = 0x0        REFCNT = 1        IO = 0x0        FORM = 0x0          AV = 0x0        HV = 0x3a8fc4        CV = 0x0        CVGEN = 0x0        LINE = 0        FILE = ""        FLAGS = 0xa        EGV = 0x3a8fe4"main::"    Elt "ENV" HASH = 0x62ffe0d6    SV = PVGV(0x285c2b4) at 0x285a55c      REFCNT = 1      FLAGS = (MULTI)      NAME = "ENV"      NAMELEN = 3      GvSTASH = 0x3a8fc4"main"      GP = 0x285e184        SV = 0x0        REFCNT = 1        IO = 0x0        FORM = 0x0          AV = 0x0        HV = 0x285a56c        CV = 0x0        CVGEN = 0x0        LINE = 0        FILE = "-e"        FLAGS = 0x2        EGV = 0x285a55c"ENV"

查看多层次模块中的内容:
D:\Tmp>perl -MDevel::Peek -e "Dump \%Devel::,1000"SV = RV(0x3a90e0) at 0x3a90d4  REFCNT = 1  FLAGS = (TEMP,ROK)  RV = 0x285a9dc  SV = PVHV(0x3ae57c) at 0x285a9dc    REFCNT = 2    FLAGS = (OOK,SHAREKEYS)    ARRAY = 0x2865534  (0:7, 1:1)    hash quality = 100.0%    KEYS = 1    FILL = 1    MAX = 7    RITER = -1    EITER = 0x0    NAME = "Devel"    BACKREFS = 0x285a9fc    SV = PVAV(0x3aa32c) at 0x285a9fc      REFCNT = 2      FLAGS = ()      ARRAY = 0x286561c      FILL = 0      MAX = 3      ARYLEN = 0x0      FLAGS = ()      Elt No. 0      SV = PVGV(0x285c334) at 0x285a9ec        REFCNT = 1        FLAGS = (MULTI)        NAME = "Peek::"        NAMELEN = 6        GvSTASH = 0x285a9dc"Devel"        GP = 0x28655dc          SV = 0x0          REFCNT = 1          IO = 0x0          FORM = 0x0            AV = 0x0          HV = 0x285aa0c          CV = 0x0          CVGEN = 0x0          LINE = 4          FILE = "D:/Perl/lib/Devel/Peek.pm"          FLAGS = 0x2          EGV = 0x285a9ec"Peek::"    Elt "Peek::" HASH = 0xf40ca9c    SV = PVGV(0x285c334) at 0x285a9ec      REFCNT = 1      FLAGS = (MULTI)      NAME = "Peek::"      NAMELEN = 6      GvSTASH = 0x285a9dc"Devel"      GP = 0x28655dc        SV = 0x0        REFCNT = 1        IO = 0x0        FORM = 0x0          AV = 0x0        HV = 0x285aa0c        CV = 0x0        CVGEN = 0x0        LINE = 4        FILE = "D:/Perl/lib/Devel/Peek.pm"        FLAGS = 0x2        EGV = 0x285a9ec"Peek::"

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