perldebguts - Perl 除錯核心
這不是 perldebug,它會告訴你如何使用偵錯器。此手冊頁面描述偵錯器內部有關低階層級的詳細資訊,對於任何對 Perl 內部結構不十分熟悉的人來說,這些資訊從困難到不可能理解。讀者請自行斟酌。
Perl 在編譯時間和執行時間具有特殊的偵錯掛鉤,用於建立偵錯環境。這些掛鉤不要與 perlrun 中所述的 perl -Dxxx 命令混淆,後者只有在按照 Perl 原始碼樹中的 INSTALL 檔案中的說明建立特殊 Perl 時才能使用。
例如,每當你從套件 DB
呼叫 Perl 內建的 caller
函數時,對應堆疊架構所呼叫的自變數會複製到 @DB::args
陣列。這些機制可透過使用 -d 開關呼叫 Perl 來啟用。特別是,會啟用下列其他功能(請參閱 "$^P" in perlvar)
Perl 會在程式的第一行之前插入 $ENV{PERL5DB}
的內容(如果不存在,則為 BEGIN {require 'perl5db.pl'}
)。
每個陣列 @{"_<$filename"}
都包含 Perl 編譯檔案的 $filename 行。對於包含子常式的 eval 字串,或目前正在執行的 eval 字串,也是如此。eval 字串的 $filename 看起來像 (eval 34)
。
此陣列中的值在數字脈絡中是神奇的:它們只有在該行不可中斷時才會等於零。
每個雜湊 %{"_<$filename"}
都包含由行號作為鍵的中斷點和動作。可以設定個別項目(與整個雜湊相反)。Perl 在這裡只關心布林值 true,儘管 perl5db.pl 所使用的值具有 "$break_condition\0$action"
的格式。
對於包含子常式的 eval 字串,或目前正在執行的 eval 字串,也是如此。eval 字串的 $filename 看起來像 (eval 34)
。
每個純量 ${"_<$filename"}
都包含 $filename
。對於包含子常式的 eval 字串,或目前正在執行的 eval 字串,也是如此。eval 字串的 $filename
看起來像 (eval 34)
。
在每個 require
的檔案編譯完成後,但在執行之前,如果 DB::postponed(*{"_<$filename"})
這個子程式存在,則會呼叫它。這裡的 $filename 是 require
的檔案經過展開的名稱,可以在 %INC 的值中找到。
在每個子程式 subname
編譯完成後,會檢查 $DB::postponed{subname}
的存在性。如果這個鍵存在,則會呼叫 DB::postponed(subname)
,如果 DB::postponed
子程式也存在的話。
會維護一個雜湊 %DB::sub
,它的鍵是子程式名稱,而它的值有 filename:startline-endline
的形式。對於在 eval
內定義的子程式,filename
有 (eval 34)
的形式。
當程式執行到達可以放置中斷點的位置時,如果 $DB::trace
、$DB::single
或 $DB::signal
這些變數中的任何一個為真,則會呼叫 DB::DB()
子程式。這些變數無法 local
化。在 DB::DB()
內執行時,這個功能會被停用,包括從中呼叫的函式,除非 $^D & (1<<30)
為真。
當程式執行到達一個子程式呼叫時,會呼叫 &DB::sub
(args) 來代替,並將 $DB::sub
設定為識別被呼叫的子程式。(如果呼叫的子程式是在 DB
套件中編譯的,則不會發生這種情況。)如果 $DB::sub
有可以查詢的名稱,則它通常會包含被呼叫子程式的名稱。如果沒有,則 $DB::sub
會包含對被呼叫子程式的參考。無論哪種方式,&DB::sub
子程式都可以使用 $DB::sub
作為呼叫被呼叫子程式的參考,而這通常是它想要做的。
如果呼叫的是 lvalue 子程式,且 &DB::lsub
有定義,則會呼叫 &DB::lsub
(args),否則會退回 &DB::sub
(args)。
當程式執行使用 goto
進入非 XS 子常式,且 $^P
中的 0x80 位元組已設定時,將呼叫 &DB::goto
,並將 $DB::sub
設定為識別已輸入的子常式。呼叫 &DB::goto
並不會取代 goto
;在 &DB::goto
返回後,仍會輸入要求的子常式。如果子常式有名稱,$DB::sub
通常會保留該名稱。如果沒有,$DB::sub
將保留對已輸入子常式的參照。與呼叫 &DB::sub
不同,無法保證 $DB::sub
可用作參照來操作已輸入的子常式。
請注意,如果 &DB::sub
需要外部資料才能運作,則在沒有資料的情況下無法呼叫子常式。例如,標準除錯器的 &DB::sub
取決於 $DB::deep
變數(它定義了在強制中斷之前,您可以在除錯器中深入遞迴的層級數)。如果未定義 $DB::deep
,則無法呼叫子常式,即使 &DB::sub
存在。
PERL5DB
環境變數可用於定義除錯器。例如,最小的「工作中」除錯器(實際上它什麼都不做)包含一行
sub DB::DB {}
可以輕鬆地這樣定義
$ PERL5DB="sub DB::DB {}" perl -d your-script
另一個簡短的除錯器,稍有用途,可以用以下一行建立
sub DB::DB {print ++$i; scalar <STDIN>}
此除錯器會列印一個數字,該數字會隨著遇到的每個陳述式而遞增,並在繼續執行下一個陳述式之前等待您按一下換行符號。
以下除錯器實際上很有用
{
package DB;
sub DB {}
sub sub {print ++$i, " $sub\n"; &$sub}
}
它會列印每個子常式呼叫的順序號碼和所呼叫子常式的名稱。請注意,&DB::sub
透過使用 package
指令編譯到套件 DB
中。
當它啟動時,除錯程式會讀取您的 rc 檔案(Unix 下的 ./.perldb 或 ~/.perldb),它可以設定重要的選項。(也可以在這裡定義一個子常式 (&afterinit
);它會在除錯程式完成自己的初始化後執行。)
在讀取 rc 檔案後,除錯程式會讀取 PERLDB_OPTS 環境變數,並用它來設定除錯程式選項。這個變數的內容會被視為除錯程式命令 o ...
的引數(請參閱 perldebug 中的「可設定選項」)。
除了上面提到的檔案和子常式相關變數外,除錯程式還會維護各種神奇的內部變數。
@DB::dbline
是 @{"::_<current_file"}
的別名,它包含目前選取檔案(由 Perl 編譯)的行,可以透過除錯程式的 f
命令明確選擇,或透過執行流程隱含選擇。
此陣列中的值在數字脈絡中是神奇的:它們只有在該行不可中斷時才會等於零。
%DB::dbline
是 %{"::_<current_file"}
的別名,它包含目前選取檔案中以行號為鍵的中斷點和動作,可以透過除錯程式的 f
命令明確選擇,或透過執行流程隱含選擇。
如前所述,可以設定個別項目(相對於整個雜湊)。Perl 在這裡只關心布林值 true,儘管 perl5db.pl 使用的值有 "$break_condition\0$action"
的形式。
提供了一些函式來簡化自訂。
請參閱 perldebug 中的「可設定選項」,以取得 DB::parse_options(string)
所分析選項的說明。
DB::dump_trace(skip[,count])
會略過指定數量的框架,並傳回一個清單,其中包含關於呼叫框架的資訊(如果缺少 count
,則包含所有框架)。每個項目都是對雜湊的參考,其鍵為 context
(.
、$
或 @
之一)、sub
(子常式名稱或關於 eval
的資訊)、args
(undef
或對陣列的參考)、file
和 line
。
DB::print_trace(FH, skip[, count[, short]])
會列印有關呼叫方框架的格式化資訊。最後兩個函式可用作 <
、<<
命令的引數。
請注意,此手冊頁面(或 perldebug)中未記載的任何變數和函式都只供內部使用,因此可能會在未經通知的情況下變更。
frame
選項可用於控制框架資訊的輸出。例如,對照此表達式追蹤
$ perl -de 42
Stack dump during die enabled outside of evals.
Loading DB routines from perl5db.pl patch level 0.94
Emacs support available.
Enter h or 'h h' for help.
main::(-e:1): 0
DB<1> sub foo { 14 }
DB<2> sub bar { 3 }
DB<3> t print foo() * bar()
main::((eval 172):3): print foo() + bar();
main::foo((eval 168):2):
main::bar((eval 170):2):
42
與此表達式,一旦設定了 o
選項 frame=2
DB<4> o f=2
frame = '2'
DB<5> t print foo() * bar()
3: foo() * bar()
entering main::foo
2: sub foo { 14 };
exited main::foo
entering main::bar
2: sub bar { 3 };
exited main::bar
42
為了示範,我們在下方提供一個繁瑣的清單,其產生方式是將您的 PERLDB_OPTS
環境變數設定為值 f=n N
,並從命令列執行 perl -d -V。會顯示使用各種 n
值的範例,讓您了解設定之間的差異。儘管很長,但這不是完整的清單,而只是摘錄。
entering main::BEGIN
entering Config::BEGIN
Package lib/Exporter.pm.
Package lib/Carp.pm.
Package lib/Config.pm.
entering Config::TIEHASH
entering Exporter::import
entering Exporter::export
entering Config::myconfig
entering Config::FETCH
entering Config::FETCH
entering Config::FETCH
entering Config::FETCH
entering main::BEGIN
entering Config::BEGIN
Package lib/Exporter.pm.
Package lib/Carp.pm.
exited Config::BEGIN
Package lib/Config.pm.
entering Config::TIEHASH
exited Config::TIEHASH
entering Exporter::import
entering Exporter::export
exited Exporter::export
exited Exporter::import
exited main::BEGIN
entering Config::myconfig
entering Config::FETCH
exited Config::FETCH
entering Config::FETCH
exited Config::FETCH
entering Config::FETCH
in $=main::BEGIN() from /dev/null:0
in $=Config::BEGIN() from lib/Config.pm:2
Package lib/Exporter.pm.
Package lib/Carp.pm.
Package lib/Config.pm.
in $=Config::TIEHASH('Config') from lib/Config.pm:644
in $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
in $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from li
in @=Config::myconfig() from /dev/null:0
in $=Config::FETCH(ref(Config), 'package') from lib/Config.pm:574
in $=Config::FETCH(ref(Config), 'baserev') from lib/Config.pm:574
in $=Config::FETCH(ref(Config), 'PERL_VERSION') from lib/Config.pm:574
in $=Config::FETCH(ref(Config), 'PERL_SUBVERSION') from lib/Config.pm:574
in $=Config::FETCH(ref(Config), 'osname') from lib/Config.pm:574
in $=Config::FETCH(ref(Config), 'osvers') from lib/Config.pm:574
in $=main::BEGIN() from /dev/null:0
in $=Config::BEGIN() from lib/Config.pm:2
Package lib/Exporter.pm.
Package lib/Carp.pm.
out $=Config::BEGIN() from lib/Config.pm:0
Package lib/Config.pm.
in $=Config::TIEHASH('Config') from lib/Config.pm:644
out $=Config::TIEHASH('Config') from lib/Config.pm:644
in $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
in $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/
out $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/
out $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
out $=main::BEGIN() from /dev/null:0
in @=Config::myconfig() from /dev/null:0
in $=Config::FETCH(ref(Config), 'package') from lib/Config.pm:574
out $=Config::FETCH(ref(Config), 'package') from lib/Config.pm:574
in $=Config::FETCH(ref(Config), 'baserev') from lib/Config.pm:574
out $=Config::FETCH(ref(Config), 'baserev') from lib/Config.pm:574
in $=Config::FETCH(ref(Config), 'PERL_VERSION') from lib/Config.pm:574
out $=Config::FETCH(ref(Config), 'PERL_VERSION') from lib/Config.pm:574
in $=Config::FETCH(ref(Config), 'PERL_SUBVERSION') from lib/Config.pm:574
in $=main::BEGIN() from /dev/null:0
in $=Config::BEGIN() from lib/Config.pm:2
Package lib/Exporter.pm.
Package lib/Carp.pm.
out $=Config::BEGIN() from lib/Config.pm:0
Package lib/Config.pm.
in $=Config::TIEHASH('Config') from lib/Config.pm:644
out $=Config::TIEHASH('Config') from lib/Config.pm:644
in $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
in $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/E
out $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/E
out $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
out $=main::BEGIN() from /dev/null:0
in @=Config::myconfig() from /dev/null:0
in $=Config::FETCH('Config=HASH(0x1aa444)', 'package') from lib/Config.pm:574
out $=Config::FETCH('Config=HASH(0x1aa444)', 'package') from lib/Config.pm:574
in $=Config::FETCH('Config=HASH(0x1aa444)', 'baserev') from lib/Config.pm:574
out $=Config::FETCH('Config=HASH(0x1aa444)', 'baserev') from lib/Config.pm:574
in $=CODE(0x15eca4)() from /dev/null:0
in $=CODE(0x182528)() from lib/Config.pm:2
Package lib/Exporter.pm.
out $=CODE(0x182528)() from lib/Config.pm:0
scalar context return from CODE(0x182528): undef
Package lib/Config.pm.
in $=Config::TIEHASH('Config') from lib/Config.pm:628
out $=Config::TIEHASH('Config') from lib/Config.pm:628
scalar context return from Config::TIEHASH: empty hash
in $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
in $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/Exporter.pm:171
out $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/Exporter.pm:171
scalar context return from Exporter::export: ''
out $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
scalar context return from Exporter::import: ''
在上述所有情況中,行縮排顯示呼叫樹狀結構。如果設定了 frame
的第 2 個位元,則在退出子常式時也會列印一行。如果設定了第 4 個位元,則會列印引數以及呼叫方資訊。如果設定了第 8 個位元,則即使引數是繫結或參考,也會列印引數。如果設定了第 16 個位元,則也會列印回傳值。
當編譯套件時,會列印類似下列的程式碼行,並適當地縮排。
Package lib/Carp.pm.
is printed with proper indentation.
有兩種方法可以啟用正規表示式的偵錯輸出。
如果您的 perl 是使用 -DDEBUGGING
編譯的,則可以在命令列上使用 -Dr 旗標,並使用 -Drv
進行更詳細的資訊。
否則,可以使用 re 'debug'
,它在編譯時和執行時都會產生效果。從 Perl 5.9.5 開始,此實用程式會以詞彙範圍為範圍。
編譯時的偵錯輸出如下所示
Compiling REx '[bc]d(ef*g)+h[ij]k$'
size 45 Got 364 bytes for offset annotations.
first at 1
rarest char g at 0
rarest char d at 0
1: ANYOF[bc](12)
12: EXACT <d>(14)
14: CURLYX[0] {1,32767}(28)
16: OPEN1(18)
18: EXACT <e>(20)
20: STAR(23)
21: EXACT <f>(0)
23: EXACT <g>(25)
25: CLOSE1(27)
27: WHILEM[1/1](0)
28: NOTHING(29)
29: EXACT <h>(31)
31: ANYOF[ij](42)
42: EXACT <k>(44)
44: EOL(45)
45: END(0)
anchored 'de' at 1 floating 'gh' at 3..2147483647 (checking floating)
stclass 'ANYOF[bc]' minlen 7
Offsets: [45]
1[4] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 5[1]
0[0] 12[1] 0[0] 6[1] 0[0] 7[1] 0[0] 9[1] 8[1] 0[0] 10[1] 0[0]
11[1] 0[0] 12[0] 12[0] 13[1] 0[0] 14[4] 0[0] 0[0] 0[0] 0[0]
0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 18[1] 0[0] 19[1] 20[0]
Omitting $` $& $' support.
第一行顯示正規表示式的預編譯形式。第二行顯示編譯形式的大小(以任意單位表示,通常為 4 位元組字元)和通常為 4+size
*8 的偏移量/長度表的總位元組數。下一行顯示執行配對的第一個節點的標籤 id。
The
anchored 'de' at 1 floating 'gh' at 3..2147483647 (checking floating)
stclass 'ANYOF[bc]' minlen 7
行(分成上面兩行)包含最佳化資訊。在顯示的範例中,最佳化器發現配對應包含在偏移量 1 的子字串 de
,加上在 3 到無限大之間某個偏移量的子字串 gh
。此外,在檢查這些子字串(以快速放棄不可能的配對)時,Perl 會在檢查子字串 de
之前檢查子字串 gh
。最佳化器也可能使用配對從字元類別(在 first
id)開始,而且沒有任何短於 7 個字元的字串可能配對的知識。
可能出現在此行中的感興趣欄位為
anchored
STRING at
POSfloating
STRING at
POS1..POS2請參閱上方。
matching floating/anchored
要先檢查哪個子字串。
minlen
配對的最小長度。
stclass
TYPE第一個配對節點的類型。
noscan
不要掃描已找到的子字串。
isall
表示最佳化器資訊就是正規表示式包含的所有內容,因此根本不需要進入正規表示式引擎。
GPOS
設定如果樣式包含 \G
。
plus
設定如果樣式以重複字元開頭(如 x+y
)。
implicit
設定如果樣式以 .*
開頭。
with eval
設定如果樣式包含 eval 群組,例如 (?{ code })
和 (??{ code })
。
anchored(TYPE)
如果樣式可能僅在少數位置配對,其中 TYPE
為 SBOL
、MBOL
或 GPOS
。請參閱下表。
如果已知子字串僅在行尾配對,則可以在其後加上 $
,例如 floating 'k'$
。
最佳化器特定資訊用於避免在無法明確配對的字串上輸入(緩慢的)正規表示法引擎。如果設定 isall
旗標,則即使最佳化器找到適當的配對位置,也可以避免呼叫正規表示法引擎。
在最佳化器區段上方是正規表示法編譯形式的 節點 清單。每行格式為
id: TYPE OPTIONAL-INFO (next-id)
以下是目前可能的類型,附有簡短說明
# TYPE arg-description [regnode-struct-suffix] [longjump-len] DESCRIPTION
# Exit points
END no End of program.
SUCCEED no Return from a subroutine, basically.
# Line Start Anchors:
SBOL no Match "" at beginning of line: /^/, /\A/
MBOL no Same, assuming multiline: /^/m
# Line End Anchors:
SEOL no Match "" at end of line: /$/
MEOL no Same, assuming multiline: /$/m
EOS no Match "" at end of string: /\z/
# Match Start Anchors:
GPOS no Matches where last m//g left off.
# Word Boundary Opcodes:
BOUND no Like BOUNDA for non-utf8, otherwise like
BOUNDU
BOUNDL no Like BOUND/BOUNDU, but \w and \W are
defined by current locale
BOUNDU no Match "" at any boundary of a given type
using /u rules.
BOUNDA no Match "" at any boundary between \w\W or
\W\w, where \w is [_a-zA-Z0-9]
NBOUND no Like NBOUNDA for non-utf8, otherwise like
BOUNDU
NBOUNDL no Like NBOUND/NBOUNDU, but \w and \W are
defined by current locale
NBOUNDU no Match "" at any non-boundary of a given
type using using /u rules.
NBOUNDA no Match "" betweeen any \w\w or \W\W, where
\w is [_a-zA-Z0-9]
# [Special] alternatives:
REG_ANY no Match any one character (except newline).
SANY no Match any one character.
ANYOF sv Match character in (or not in) this class,
charclass single char match only
ANYOFD sv Like ANYOF, but /d is in effect
charclass
ANYOFL sv Like ANYOF, but /l is in effect
charclass
ANYOFPOSIXL sv Like ANYOFL, but matches [[:posix:]]
charclass_ classes
posixl
ANYOFH sv 1 Like ANYOF, but only has "High" matches,
none in the bitmap; the flags field
contains the lowest matchable UTF-8 start
byte
ANYOFHb sv 1 Like ANYOFH, but all matches share the same
UTF-8 start byte, given in the flags field
ANYOFHr sv 1 Like ANYOFH, but the flags field contains
packed bounds for all matchable UTF-8 start
bytes.
ANYOFHs sv:str 1 Like ANYOFHb, but has a string field that
gives the leading matchable UTF-8 bytes;
flags field is len
ANYOFR packed 1 Matches any character in the range given by
its packed args: upper 12 bits is the max
delta from the base lower 20; the flags
field contains the lowest matchable UTF-8
start byte
ANYOFRb packed 1 Like ANYOFR, but all matches share the same
UTF-8 start byte, given in the flags field
ANYOFHbbm none bbm Like ANYOFHb, but only for 2-byte UTF-8
characters; uses a bitmap to match the
continuation byte
ANYOFM byte 1 Like ANYOF, but matches an invariant byte
as determined by the mask and arg
NANYOFM byte 1 complement of ANYOFM
# POSIX Character Classes:
POSIXD none Some [[:class:]] under /d; the FLAGS field
gives which one
POSIXL none Some [[:class:]] under /l; the FLAGS field
gives which one
POSIXU none Some [[:class:]] under /u; the FLAGS field
gives which one
POSIXA none Some [[:class:]] under /a; the FLAGS field
gives which one
NPOSIXD none complement of POSIXD, [[:^class:]]
NPOSIXL none complement of POSIXL, [[:^class:]]
NPOSIXU none complement of POSIXU, [[:^class:]]
NPOSIXA none complement of POSIXA, [[:^class:]]
CLUMP no Match any extended grapheme cluster
sequence
# Alternation
# BRANCH The set of branches constituting a single choice are
# hooked together with their "next" pointers, since
# precedence prevents anything being concatenated to
# any individual branch. The "next" pointer of the last
# BRANCH in a choice points to the thing following the
# whole choice. This is also where the final "next"
# pointer of each individual branch points; each branch
# starts with the operand node of a BRANCH node.
#
BRANCH node 1 Match this alternative, or the next...
# Literals
EXACT str Match this string (flags field is the
length).
# In a long string node, the U32 argument is the length, and is
# immediately followed by the string.
LEXACT len:str 1 Match this long string (preceded by length;
flags unused).
EXACTL str Like EXACT, but /l is in effect (used so
locale-related warnings can be checked for)
EXACTF str Like EXACT, but match using /id rules;
(string not UTF-8, ASCII folded; non-ASCII
not)
EXACTFL str Like EXACT, but match using /il rules;
(string not likely to be folded)
EXACTFU str Like EXACT, but match using /iu rules;
(string folded)
EXACTFAA str Like EXACT, but match using /iaa rules;
(string folded except MICRO in non-UTF8
patterns; doesn't contain SHARP S unless
UTF-8; folded length <= unfolded)
EXACTFAA_NO_TRIE str Like EXACTFAA, (string not UTF-8, folded
except: MICRO, SHARP S; folded length <=
unfolded, not currently trie-able)
EXACTFUP str Like EXACT, but match using /iu rules;
(string not UTF-8, folded except MICRO:
hence Problematic)
EXACTFLU8 str Like EXACTFU, but use /il, UTF-8, (string
is folded, and everything in it is above
255
EXACT_REQ8 str Like EXACT, but only UTF-8 encoded targets
can match
LEXACT_REQ8 len:str 1 Like LEXACT, but only UTF-8 encoded targets
can match
EXACTFU_REQ8 str Like EXACTFU, but only UTF-8 encoded
targets can match
EXACTFU_S_EDGE str /di rules, but nothing in it precludes /ui,
except begins and/or ends with [Ss];
(string not UTF-8; compile-time only)
# New charclass like patterns
LNBREAK none generic newline pattern
# Trie Related
# Behave the same as A|LIST|OF|WORDS would. The '..C' variants
# have inline charclass data (ascii only), the 'C' store it in the
# structure.
TRIE trie 1 Match many EXACT(F[ALU]?)? at once.
flags==type
TRIEC trie Same as TRIE, but with embedded charclass
charclass data
AHOCORASICK trie 1 Aho Corasick stclass. flags==type
AHOCORASICKC trie Same as AHOCORASICK, but with embedded
charclass charclass data
# Do nothing types
NOTHING no Match empty string.
# A variant of above which delimits a group, thus stops optimizations
TAIL no Match empty string. Can jump here from
outside.
# Loops
# STAR,PLUS '?', and complex '*' and '+', are implemented as
# circular BRANCH structures. Simple cases
# (one character per match) are implemented with STAR
# and PLUS for speed and to minimize recursive plunges.
#
STAR node Match this (simple) thing 0 or more times:
/A{0,}B/ where A is width 1 char
PLUS node Match this (simple) thing 1 or more times:
/A{1,}B/ where A is width 1 char
CURLY sv 3 Match this (simple) thing {n,m} times:
/A{m,n}B/ where A is width 1 char
CURLYN no 3 Capture next-after-this simple thing:
/(A){m,n}B/ where A is width 1 char
CURLYM no 3 Capture this medium-complex thing {n,m}
times: /(A){m,n}B/ where A is fixed-length
CURLYX sv 3 Match/Capture this complex thing {n,m}
times.
# This terminator creates a loop structure for CURLYX
WHILEM no Do curly processing and see if rest
matches.
# Buffer related
# OPEN,CLOSE,GROUPP ...are numbered at compile time.
OPEN num 1 Mark this point in input as start of #n.
CLOSE num 1 Close corresponding OPEN of #n.
SROPEN none Same as OPEN, but for script run
SRCLOSE none Close preceding SROPEN
REF num 2 Match some already matched string
REFF num 2 Match already matched string, using /di
rules.
REFFL num 2 Match already matched string, using /li
rules.
REFFU num 2 Match already matched string, usng /ui.
REFFA num 2 Match already matched string, using /aai
rules.
# Named references. Code in regcomp.c assumes that these all are after
# the numbered references
REFN no-sv 2 Match some already matched string
REFFN no-sv 2 Match already matched string, using /di
rules.
REFFLN no-sv 2 Match already matched string, using /li
rules.
REFFUN num 2 Match already matched string, using /ui
rules.
REFFAN num 2 Match already matched string, using /aai
rules.
# Support for long RE
LONGJMP off 1 1 Jump far away.
BRANCHJ off 2 1 BRANCH with long offset.
# Special Case Regops
IFMATCH off 1 1 Succeeds if the following matches; non-zero
flags "f", next_off "o" means lookbehind
assertion starting "f..(f-o)" characters
before current
UNLESSM off 1 1 Fails if the following matches; non-zero
flags "f", next_off "o" means lookbehind
assertion starting "f..(f-o)" characters
before current
SUSPEND off 1 1 "Independent" sub-RE.
IFTHEN off 1 1 Switch, should be preceded by switcher.
GROUPP num 1 Whether the group matched.
# The heavy worker
EVAL evl/flags Execute some Perl code.
2
# Modifiers
MINMOD no Next operator is not greedy.
LOGICAL no Next opcode should set the flag only.
# This is not used yet
RENUM off 1 1 Group with independently numbered parens.
# Regex Subroutines
GOSUB num/ofs 2 recurse to paren arg1 at (signed) ofs arg2
# Special conditionals
GROUPPN no-sv 1 Whether the group matched.
INSUBP num 1 Whether we are in a specific recurse.
DEFINEP none 1 Never execute directly.
# Backtracking Verbs
ENDLIKE none Used only for the type field of verbs
OPFAIL no-sv 1 Same as (?!), but with verb arg
ACCEPT no-sv/num Accepts the current matched string, with
2 verbar
# Verbs With Arguments
VERB no-sv 1 Used only for the type field of verbs
PRUNE no-sv 1 Pattern fails at this startpoint if no-
backtracking through this
MARKPOINT no-sv 1 Push the current location for rollback by
cut.
SKIP no-sv 1 On failure skip forward (to the mark)
before retrying
COMMIT no-sv 1 Pattern fails outright if backtracking
through this
CUTGROUP no-sv 1 On failure go to the next alternation in
the group
# Control what to keep in $&.
KEEPS no $& begins here.
# Validate that lookbehind IFMATCH and UNLESSM end at the right place
LOOKBEHIND_END no Return from lookbehind (IFMATCH/UNLESSM)
and validate position
# SPECIAL REGOPS
# This is not really a node, but an optimized away piece of a "long"
# node. To simplify debugging output, we mark it as if it were a node
OPTIMIZED off Placeholder for dump.
# Special opcode with the property that no opcode in a compiled program
# will ever be of this type. Thus it can be used as a flag value that
# no other opcode has been seen. END is used similarly, in that an END
# node cant be optimized. So END implies "unoptimizable" and PSEUDO
# mean "not seen anything to optimize yet".
PSEUDO off Pseudo opcode for internal use.
REGEX_SET depth p Regex set, temporary node used in pre-
optimization compilation
在最佳化器資訊之後,是偏移量/長度表的轉儲,這裡分為多行
Offsets: [45]
1[4] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 5[1]
0[0] 12[1] 0[0] 6[1] 0[0] 7[1] 0[0] 9[1] 8[1] 0[0] 10[1] 0[0]
11[1] 0[0] 12[0] 12[0] 13[1] 0[0] 14[4] 0[0] 0[0] 0[0] 0[0]
0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 18[1] 0[0] 19[1] 20[0]
此處的第一行表示偏移量/長度表格包含 45 個項目。每個項目都是一對整數,表示為 offset[length]
。項目編號從 1 開始,因此此處的項目 #1 為 1[4]
,項目 #12 為 5[1]
。1[4]
表示標籤為 1:
的節點(1: ANYOF[bc]
)在正規表示式的預編譯形式中從字元位置 1 開始,長度為 4 個字元。位置 12 中的 5[1]
表示標籤為 12:
的節點(12: EXACT <d>
)在正規表示式的預編譯形式中從字元位置 5 開始,長度為 1 個字元。位置 14 中的 12[1]
表示標籤為 14:
的節點(14: CURLYX[0] {1,32767}
)在正規表示式的預編譯形式中從字元位置 12 開始,長度為 1 個字元---也就是說,它對應於預編譯正規表示式中的 +
符號。
0[0]
項目表示沒有對應的節點。
首先,執行比對時,即使已啟用偵錯,也可能沒有執行時期輸出。這表示從未進入正規表示式引擎,因此所有工作都由最佳化器完成。
如果已進入正規表示式引擎,輸出可能會如下所示
Matching '[bc]d(ef*g)+h[ij]k$' against 'abcdefg__gh__'
Setting an EVAL scope, savestack=3
2 <ab> <cdefg__gh_> | 1: ANYOF
3 <abc> <defg__gh_> | 11: EXACT <d>
4 <abcd> <efg__gh_> | 13: CURLYX {1,32767}
4 <abcd> <efg__gh_> | 26: WHILEM
0 out of 1..32767 cc=effff31c
4 <abcd> <efg__gh_> | 15: OPEN1
4 <abcd> <efg__gh_> | 17: EXACT <e>
5 <abcde> <fg__gh_> | 19: STAR
EXACT <f> can match 1 times out of 32767...
Setting an EVAL scope, savestack=3
6 <bcdef> <g__gh__> | 22: EXACT <g>
7 <bcdefg> <__gh__> | 24: CLOSE1
7 <bcdefg> <__gh__> | 26: WHILEM
1 out of 1..32767 cc=effff31c
Setting an EVAL scope, savestack=12
7 <bcdefg> <__gh__> | 15: OPEN1
7 <bcdefg> <__gh__> | 17: EXACT <e>
restoring \1 to 4(4)..7
failed, try continuation...
7 <bcdefg> <__gh__> | 27: NOTHING
7 <bcdefg> <__gh__> | 28: EXACT <h>
failed...
failed...
輸出中最重要的資訊是關於目前針對目標字串測試的編譯正規表示式特定節點。這些行的格式為
字串偏移量 <字串前> <字串後> |ID: 類型
TYPE 資訊會根據回溯層級縮排。其他附帶資訊會穿插顯示在其中。
Perl 在使用記憶體時很浪費。有句諺語說,要估計 Perl 的記憶體使用量,假設一個合理的記憶體配置演算法,將估計值乘以 10,即使這樣還是可能估計錯誤,但至少不會太驚訝。這句話並非完全正確,但可以很好地掌握發生了什麼事。
假設一個整數不能少於 20 個位元組的記憶體,一個浮點數不能少於 24 個位元組,一個字串不能少於 32 個位元組(所有這些範例都假設是 32 位元架構,在 64 位元架構中結果會更糟)。如果一個變數以三種不同方式中的兩種方式存取(需要一個整數、一個浮點數或一個字串),記憶體使用量可能會再增加 20 個位元組。一個隨便的 malloc(3) 實作會大幅增加這些數字。
在範圍的另一端,像這樣的宣告
sub foo;
可能會佔用多達 500 個位元組的記憶體,具體取決於您執行的 Perl 版本。
來源到編譯程式碼膨脹的軼事估計表明會增加八倍。這表示合理的(通常有註解、正確縮排等)程式碼的編譯形式將佔用比程式碼在磁碟上佔用的空間大約多八倍的記憶體。
自 Perl 5.6.0 以來,-DL 命令列開關已過時(僅當 Perl 使用 -DDEBUGGING
建置時才可用)。此開關用於追蹤 Perl 的記憶體配置和可能的記憶體外洩。現在建議改用 malloc 除錯工具,例如 Purify 或 valgrind。另請參閱 perlhacktips 中的「PERL_MEM_LOG」。
找出 Perl 資料結構使用多少記憶體的一種方法是從 CPAN 安裝 Devel::Size 模組:它會提供儲存特定資料結構所需的最小位元組數。請注意 size() 和 total_size() 之間的差異。
如果 Perl 已使用 Perl 的 malloc 編譯,您可以透過設定 $ENV{PERL_DEBUG_MSTATS} 來分析 Perl 記憶體使用情況。
$ENV{PERL_DEBUG_MSTATS}
如果您的 perl 使用 Perl 的 malloc(),且已使用必要的開關編譯(這是預設值),則在編譯您的程式碼後,當 $ENV{PERL_DEBUG_MSTATS} > 1
時,它會列印記憶體使用情況統計資料;在程式終止前,當 $ENV{PERL_DEBUG_MSTATS} >= 1
時,它也會列印統計資料。報告格式類似於以下範例
$ PERL_DEBUG_MSTATS=2 perl -e "require Carp"
Memory allocation statistics after compilation: (buckets 4(4)..8188(8192)
14216 free: 130 117 28 7 9 0 2 2 1 0 0
437 61 36 0 5
60924 used: 125 137 161 55 7 8 6 16 2 0 1
74 109 304 84 20
Total sbrk(): 77824/21:119. Odd ends: pad+heads+chain+tail: 0+636+0+2048.
Memory allocation statistics after execution: (buckets 4(4)..8188(8192)
30888 free: 245 78 85 13 6 2 1 3 2 0 1
315 162 39 42 11
175816 used: 265 176 1112 111 26 22 11 27 2 1 1
196 178 1066 798 39
Total sbrk(): 215040/47:145. Odd ends: pad+heads+chain+tail: 0+2192+0+6144.
您可以使用標準 Devel::Peek 模組中的 mstat() 函數,在執行中的任意點要求此類統計資料。
以下是該格式的一些說明
區塊 SMALLEST(APPROX)..GREATEST(APPROX)
Perl 的 malloc() 使用區塊分配。每個要求都會向上取整至最接近的可用區塊大小,並從該大小的區塊池中取出一個區塊。
上述行描述目前使用中區塊的限制。每個區塊有兩種大小:記憶體使用量和可放入此區塊的使用者資料最大大小。假設在上述範例中,最小區塊大小為 4。最大區塊的可使用大小為 8188,記憶體使用量為 8192。
在為偵錯而建置的 Perl 中,有些區塊可能具有負的可使用大小。這表示這些區塊無法(也不會)被使用。對於較大的區塊,記憶體使用量可能比 2 的次方大一頁。如果是這樣,上述 APPROX
欄位中會列印對應的 2 的次方。
隨後的一或兩列數字對應於 SMALLEST
和 GREATEST
之間每個大小的區塊數。在第一列中,區塊的大小(記憶體使用量)是 2 的次方,或可能大一頁。在第二列中(如果存在),區塊的記憶體使用量介於「上方」兩個區塊的記憶體使用量之間。
例如,假設在先前的範例中,記憶體使用量為
free: 8 16 32 64 128 256 512 1024 2048 4096 8192
4 12 24 48 80
使用非DEBUGGING
perl 時,從128
開始的儲存區有 4 位元組的額外負擔,因此長度為 8192 的儲存區可能需要多達 8188 位元組的配置。
Total sbrk(): SBRKed/SBRKs:CONTINUOUS
前兩個欄位提供 perl sbrk(2)ed (ess-broken? :-) 的總記憶體量和使用的 sbrk(2) 數量。第三個數字是 perl 認為的傳回區塊的連續性。只要這個數字為正,malloc() 就會假設 sbrk(2) 可能會提供連續記憶體。
外部函式庫配置的記憶體不會計算在內。
pad: 0
保持儲存區對齊所需的 sbrk(2)ed 記憶體量。
heads: 2192
雖然較大儲存區的記憶體額外負擔會保留在儲存區內,但對於較小的儲存區,則會保留在個別區域中。此欄位提供這些區域的總大小。
chain: 0
malloc() 可能會想要將較大的儲存區細分為較小的儲存區。如果已故儲存區中只有一部分未細分,其餘部分將保留為連結清單的元素。此欄位提供這些區塊的總大小。
tail: 6144
為了將 sbrk(2) 的數量降至最低,malloc() 會要求更多的記憶體。此欄位提供尚未使用的部分的大小,此部分已 sbrk(2)ed,但從未觸及。