這個公衆號以前的文章,分享的都是Jerry和SAP成都研究院的同事在工做中學到的一些知識和感覺。而今天這篇文章,寫做的由來是由於最近我又參與了SAP成都數字創新空間應聘者的面試,和一些朋友聊了一些關於用不一樣的編程語言寫Hello World程序的話題,忽然才發現,本身從2007年畢業以後,再沒有使用過C語言進行編程了。所以想作一個簡單的回憶。對C語言不感興趣的ABAP開發顧問,能夠直接跳到本文講ABAP的章節。面試
爲何這篇文章要把C語言和ABAP放在一塊兒講,而不是別的語言好比Java和ABAP呢?由於ABAP語言底層是基於C/C++實現的,包括其關鍵字(好比最簡單的關鍵字WRITE的C++實現有2千多行)和虛擬機(ABAP Runtime)。SAP內部的一羣計算機科學家們發明了ABAP這門偉大的語言,由它實現的各類SAP應用幫助了全球超過180個國家和地區的客戶們更好地運行其業務。算法
經過Google咱們能搜索到一些關於這些SAP計算機科學家們的介紹,好比這個連接:數據庫
好比像下圖這種用kernel module修飾的sc_km_check_feature_2, 以及每個ABAP關鍵字,其C語言的實現代碼在SAP內部的Netweaver系統能夠查看到,可是在客戶系統上,則是以二進制目標文件的形式存儲,沒法查看源代碼。數據結構
本文的目的是但願經過C語言和ABAP編譯過程的一些介紹,加深ABAP顧問們對這門語言的理解。編程語言
用C語言寫個Hello World程序,另存爲study.c:工具
用命令行gcc ./study.c --verbose進行編譯,參數verbose可供咱們查看編譯明細。上述命令行在個人Ubuntu系統上產生一串長長的輸出:學習
咱們能夠一步步分析。首先用參數 -E查看預處理生成的目標文件study.i:區塊鏈
gcc -E study.c -o study.i測試
能夠看到源代碼文件只有78字節,編譯預處理後生成的輸出文件有17116字節。
爲何膨脹了這麼多?緣由是由於我源代碼文件的第一行,#include<stdio.h>被預處理器替換成了stdio.h的實際內容,而stdio.h裏若是又存在#include其餘文件的聲明,這個替換過程會遞歸執行。所以直到study.i的末尾部分,咱們才能看到在study.c裏書寫的源代碼部分。
源代碼文件study.c裏的第一行語句 #include<stdio.h>, 請你們記住,後面講ABAP還會提到。
用命令行gcc -S能夠查看study.c編譯後生成的彙編代碼:
看到這些pushq, popq, %rbp,Jerry不禁得想起本科彙編程序設計專業課上,我和寢室其餘兄弟坐在教室最後一排看體壇週報的時光。
工做十多年後,Jerry不得不認可,當時本科開設的計算機專業課,像數據結構,操做系統,計算機組成原理,編譯原理,彙編程序設計,計算機圖形學這些都是有用的,工做後,公司不可能再給你時間去學習這些基礎理論知識了。
雖然彙編程序設計這門課Jerry當初沒有好好學,但至少教材我是妥善保存了的,以防哪天公司的工做安排鬚要讓我把十多年前在學校學的東西從新又撿起來。
下面咱們來聊聊ABAP。
SAP note 1230076 」Generation of ABAP loads: Tips for the analysis」 介紹了一個工具程序:RSDEPEND。這個note提到,一個即使看起來最簡單的ABAP Hello World報表,其實也依賴於許多標準的Repository對象,這些依賴咱們假定稱其爲A,B,C。假設A,B,C其中有任何一個有改動產生,好比A是一個include程序,裏面使用到了一個DDIC結構,在某個時刻,系統導入了一個傳輸請求(Transport Request), 裏面包含了針對這個DDIC結構的更改,那麼此時這個最簡單的Hello World報表的load就成爲了obsolete狀態。在從新執行該報表以前,ABAP Runtime(中文譯成ABAP運行時)會自動作一個load invalidation操做,生成一個最新版本的load。
什麼是ABAP load?看ABAP help裏的官方定義:
「In the ABAP environment, a load describes a binary representation of a repository object which is optimized for fast access, in the memory or on the database.」
翻譯成中文:ABAP load是Repository對象的二進制表現形式,針對ABAP環境的快速訪問而作過特別優化,能夠存儲在數據庫表中或者加載於內存裏。
咱們用一個實際的例子來理解ABAP報表激活和運行時發生的事情。
建立一張很是簡單的透明表ZLOADTEST:
寫一個簡單的報表,命名爲ZTESTLOAD。報表的源代碼以壓縮的格式存儲在表REPOSRC的DATA字段裏。
測試報表的源代碼很簡單,把表裏的數據所有讀取出來:
激活這個簡單的報表(是的,在ABAP世界裏,咱們習慣說激活,而不是編譯)。激活後生成的ABAP load存儲在表REPOLOAD的字段LDATA和QDATA裏。
這兩個字段存儲的內容就是前面ABAP help提到的ABAP load在數據庫表中的存儲形式。
菜單Goto->Navigate to->Switch to Classic Debugger:
Goto->System Areas->Internal Information:
在System Area區域輸入CONT,就能在下圖的NAME列看到ABAP load裏包含的指令。固然同開源的JVM不一樣,JVM字節碼指令集在網上可以查到,而這些ABAP load的指令是SAP internal的,所以不能在這裏作解釋。
而後執行前面提到的工具報表RSDEPEND, 輸入參數program name = ZTESTLOAD, 獲得結果,其中測試報表的ABAP Load時間戳爲07:21:02, 這個報表依賴的標準Include有:
<REPINI>
<SYSINI>
<SYSSEL>
DB__SSEL
由此看出,每個標準的ABAP報表都自動包含了這些include。若是開發人員顯式地再包含其中任意一個,會遇到語法錯誤: Module %_PF_STATUS is already defined as a OUTPUT module.
你們以爲這個<REPINI>是否是很像前文C語言部分提到的#include<stdio.h>?
下面咱們再作幾輪測試。
測試1
修改透明表的描述信息,而後從新激活透明表。
執行RSDEPEND, 能夠看到只有透明表的Last Changed字段發生了變化,ABAP Time Stamp和Screen Time Stamp都不變,這是咱們指望的結果,由於咱們只是修改了透明表的描述信息,並未修改結構。
再次執行測試報表ZTESTLOAD, 用RSDEPEND檢測,發現測試報表的ABAP Load時間戳沒有發生變化,這說明:即便依賴的透明表的描述信息發生變化,使用了該透明表的ABAP報表不須要從新編譯,由於透明表描述信息不須要在報表執行期使用。
測試2
給透明表增長新的一列,再次激活。
此時經過RSDEPEND發現,透明表的三個時間戳所有發生了變化,以下圖藍色矩形框所示。然而測試報表ABAP Load自己的時間戳仍然未變,這也是合理的,由於咱們給透明表裏增長了新的列後,還未執行測試報表。
再次執行ZTESTLOAD後,此次發現它的ABAP Load已經被自動invalidate了,時間戳從07:21:02變成了07:36:02。
這也解釋了一個現象:有的朋友們觀察到,當系統剛升完級後,或者有一批新的傳輸請求導入到系統後,第一次使用SAP應用時,系統響應速度很慢。緣由其實經過前文的兩個測試已經說明了:系統在花費時間去作相關ABAP Load invalidation。在應用依賴的這些Load invalidation沒有結束以前,系統沒法響應用戶請求。
爲了不用戶在第一次使用應用時長時間等待,可使用事務碼SGEN預先進行Load invalidation。SGEN詳細的使用方法能夠參考下面這篇文章
但願這篇文章能給那些想了解ABAP語言底層一些實現細節的顧問朋友們有所幫助。
更多閱讀
要獲取更多Jerry的原創文章,請關注公衆號"汪子熙":