靈修分享:亞略巴古的演講

亞略巴古的演說是使徒行傳一篇非常著名的講道。基督徒往往用這段經文來說明上帝的屬性,同時也會參考這段經文作為和外邦人互動的一個參考方式。最近因為團契查經查到這一段,重新思想後看到了以前沒有考慮過的面向,在這邊記錄一下。

徒17:16-34保羅在雅典等候他們的時候,看見滿城都是偶像,就心裏着急;於是在會堂裏與猶太人和虔敬的人,並每日在市上所遇見的人,辯論。還有伊壁鳩魯和斯多亞兩門的學士,與他爭論。有的說:「這胡言亂語的要說甚麼?」有的說:「他似乎是傳說外邦鬼神的。」這話是因保羅傳講耶穌與復活的道。他們就把他帶到亞略‧巴古,說:「你所講的這新道,我們也可以知道嗎?因為你有些奇怪的事傳到我們耳中,我們願意知道這些事是甚麼意思。」(雅典人和住在那裏的客人都不顧別的事,只將新聞說說聽聽。)
保羅站在亞略‧巴古當中,說:「眾位雅典人哪,我看你們凡事很敬畏鬼神。我遊行的時候,觀看你們所敬拜的,遇見一座壇,上面寫着『未識之神』。你們所不認識而敬拜的,我現在告訴你們。創造宇宙和其中萬物的神,既是天地的主,就不住人手所造的殿,也不用人手服事,好像缺少甚麼;自己倒將生命、氣息、萬物,賜給萬人。他從一本本:有古卷是血脈造出萬族的人,住在全地上,並且預先定準他們的年限和所住的疆界,要叫他們尋求神,或者可以揣摩而得,其實他離我們各人不遠;我們生活、動作、存留,都在乎他。就如你們作詩的,有人說:『我們也是他所生的。』我們既是神所生的,就不當以為神的神性像人用手藝、心思所雕刻的金、銀、石。世人蒙昧無知的時候,神並不監察,如今卻吩咐各處的人都要悔改。因為他已經定了日子,要藉着他所設立的人按公義審判天下,並且叫他從死裏復活,給萬人作可信的憑據。」
眾人聽見從死裏復活的話,就有譏誚他的;又有人說:「我們再聽你講這個吧!」於是保羅從他們當中出去了。 但有幾個人貼近他,信了主,其中有亞略‧巴古的官丟尼修,並一個婦人,名叫大馬哩,還有別人一同信從。

對基督徒來說,保羅這篇講道講的真好,不但講出了上帝的超越性(像是不住人手所造的殿、也不是金銀石的彫刻),也帶出了耶穌基督復活的大能。但最近我才注意到眾人的反應:「眾人聽見從死裏復活的話,就有譏誚他的;又有人說:「我們再聽你講這個吧!」」不曉得你看到這一段有什麼感想?可能我是玻璃心吧,如果我是保羅,我大概會非常非常的難過,看起來似乎沒有人理會這個福音、這篇講道。這篇被基督…

Slab allocation

雖然 Linux 的相關文章發表了不少,有些看起來也很有深度(只是看起來),但其實我沒有這麼大的熱情去了解 Linux 的核心運作。通常都是我遇到一個奇怪的現象或是想了解某一個問題才會認真的去看 kernel 的程式碼。今天要介紹的東西也是如此,先說明一下發生的情境(按照慣例,全部不打人名):

同事A:我使用 OSW_MEMALLOC (相當於 malloc,只是考慮到跨平台的問題,我們團隊開發了套介面來加以包裝)以後,結果它告訴我分配出來的記憶體已經被使用了 ...

這樣的描述讓我覺得很有趣(至於造成這個現象的問題就一點都不想贅述,反正就是有人 pointer 使用上出了包),有趣的點在於,malloc 會跟系統要一塊空間,如果系統記憶體用光無法分派這我可以理解(反正就是有人寫了 memory leak 的程式),但是,怎麼有可能系統分派了空間在告訴你說這塊空間有人使用呢??

在另外一位同事(Parrot)的幫助之下,我開始看 Linux Kernel 的記憶體的一些處理方式,並找到了這個問題的答案。

在開始看之前,我們先來介紹一下 Slab Allocator 這個東西。Slab Allocator 由 Sun 的工程師所提出來的 memory allocator。基本的概念可以參考下面的文章(取自 wikipedia):

The fundamental idea behind slab allocation technique is based on the observation that some kernel data objects are frequently created and destroyed after they are not needed anymore. This implies that for each allocation of memory for these data objects, some time is spent to find the best fit for that data object. Moreover, deallocation of the memory after destruction of the object contributes to fragmentation of the memory, which burdens the kernel some more to rearrange the memory.

With slab allocation, using certain system calls by the programmer, memory chunks suitable to fit data objects of certain type or size are preallocated. The slab allocator keeps track of these chunks, known as caches, so that when a request to allocate memory for a data object of certain size is received it can instantly satisfy the request with an already allocated slot. Destruction of the object, however, does not free up the memory, but only opens a slot which is put in the list of free slots by the slab allocator. The next call to allocate memory of the same size will return the now unused memory slot. This process eliminates the need to search for suitable memory space and greatly alleviates memory fragmentation. In this context a slab is one or more contiguous pages in the memory containing pre-allocated memory chunks.

簡單來說就是一個 memory pool 的概念,一開始 slab allocator 就跟作業系統要了一塊空間,當使用者透過 malloc 來要記憶體的時候,其實 slab allocator 會從已經分派好的空間中取出還沒用過的部份回傳而不用核心要 pages。而 free 的話就是直接把不用的記憶體丟回給 pool 裡面。而為甚麼 slab allocator 的介面會比核心來的有效率呢(土黃色的部份)?首先,SLAB最上層為一個由多個 kmem_cache 組成的 cache chain。每個 kmem_cache 由 slabs_full,slabs_partial,slabs_empty這 3 個 list 組成。新的slab申請到達時,slab_partial 頁會被考慮;一個內存塊釋放時 slab_empty將被優先考慮。

好,但到這裡我還沒打算進去研究 code,理由很簡單, slab 的繼承人出現了~ SLUB。Slub 和 Slab 比起來,最大的差別就是它簡化了 structure 的部份(從網路上看來的,而且我不想再看下去 :p )。

回到最原始的問題,系統如何檢查 memory 是否有被用過呢?

在 linux-2.6.28.7/mm/slub.c 裡面,我找到了下面這一隻 function:

static int check_object(struct kmem_cache *s, struct page *page,
void *object, int active)
{
____u8 *p = object;
____u8 *endobject = object + s->objsize;

____if (s->flags & SLAB_RED_ZONE) {
________unsigned int red = active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE;

________if (!check_bytes_and_report(s, page, object, "Redzone", endobject, red, s->inuse - s->objsize))
________return 0;
____} else {
________if ((s->flags & SLAB_POISON) && s->objsize <>inuse) {
____________check_bytes_and_report(s, page, p, "Alignment padding", endobject, POISON_INUSE, s->inuse - s->objsize);
________}
____}

____if (s->flags & SLAB_POISON) {
________if (!active && (s->flags & __OBJECT_POISON) &&
____________(!check_bytes_and_report(s, page, p, "Poison", p,
________________POISON_FREE, s->objsize - 1) ||
____________!check_bytes_and_report(s, page, p, "Poison",
____________p + s->objsize - 1, POISON_END, 1)))
____________return 0;
________/*
________ * check_pad_bytes cleans up on its own.
________ */
________check_pad_bytes(s, page, p);
____}

____if (!s->offset && active)
________/*
________ * Object and freepointer overlap. Cannot check
________ * freepointer while object is allocated.
________*/
________return 1;

____/* Check free pointer validity */
____if (!check_valid_pointer(s, page, get_freepointer(s, p))) {
________object_err(s, page, p, "Freepointer corrupt");
________/*
________* No choice but to zap it and thus loose the remainder
________ * of the free objects in this slab. May cause
________ * another error because the object count is now wrong.
________ */
________set_freepointer(s, p, NULL);
________return 0;
____}
____return 1;
}

看到了紅色所標明來的關鍵字,大概可以猜出一個運作邏輯:當使用者呼叫 allocate 的時候,slub 會將分配出來的記憶體填成 POISON_INUSE,free 的時候則填成 POISON_FREE。

以程式來看還挺像的,在 new_slab 的時候有將 memory 設成 POISON_INUSE;而在 init_object 的時候則設成了 POISON_FREE (最後一個為 POISON_END)

BTW,

#define POISON_INUSE 0x5a
#define POISON_FREE 0x6b
#define POISON_END 0xa5

留言

這個網誌中的熱門文章

如何將Linux打造成OpenFlow Switch:Openvswitch

我弟家的新居感恩禮拜分享:善頌善禱

如何利用 Wireshark 來監聽 IEEE 802.11 的管理封包