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

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,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,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,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,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::,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的整体有一个了解,相信其他语言也有类似的概念结构来实现命名空间的引入。

相关文章

1. 如何去重 #!/usr/bin/perl use strict; my %hash; while(...
最近写了一个perl脚本,实现的功能是将表格中其中两列的数据...
表的数据字典格式如下:如果手动写MySQL建表语句,确认麻烦,...
巡检类工作经常会出具日报,最近在原有日报的基础上又新增了...
在实际生产环境中,常常需要从后台日志中截取报文,报文的形...
最近写的一个perl程序,通过关键词匹配统计其出现的频率,让...