IEC 61508標準強烈推薦使用靜態內存管理方式。在安全應用設計中,我們都在遵循這個建議。但我們可能會需要這樣的功能:
? 運行時配置
? 刪除組件的編譯時配置
? 更靈活的控制外部行為或硬件
? 平臺作為完整的一代產品
這些功能需要動態內存管理解決方案。
IEC61508中推薦使用靜態內存管理方式的原因與動態內存管理相關的編程錯誤導致的潛在風險相關,我們必須避免和發現這些編程錯誤,潛在風險包括:
1 內存碎片
2 沒有可用內存
3 空閑內存丟失
4 內存釋放到錯誤內存池
5 內存多次釋放
6 釋放后繼續使用內存
7 使用時釋放內存
一類解決方案只允許分配內存,這類解決方案通過避免內存重用來解決上述問題中的3-7,這是一種有效的解決方案,通常用于不同產品變體啟動期間中的內存靈活配置,在運行期間保持內存布局不變。
當這類方法不能滿足需求時,我們需要一種更通用的方法來系統地避免或檢測所有列出的風險情況。
1內存碎片
內存碎片是一種效應,當我們使用不同的內存大小執行多個分配和釋放周期時可能會產生這種效應。
在實時系統中,我們需要確定性和恒定的執行時間。使用改進的分配算法(如首次適配算法),執行時間嚴重將依賴于以前的內存活動,這對我們的系統設計是不利的。
避免內存碎片的方法是使用一個(或一組)固定大小的內存塊池。好消息是專業的實時內核為用戶提供了固定大小內存塊的內存管理機制,用戶可以使用實時內核提供的這些服務。在本文中,我們考慮實時內核的主函數接口。
作為參考,一個簡單的使用序列為:
ptr =MemAlloc(pool); /* use memory via ptr */ MemFree(pool, ptr);
在啟動過程中調用:
pool= Create(mem, size, num);
2沒有可用內存
如果沒有足夠的內存滿足當前分配請求,內存分配函數會反饋相應信息(如NULL指針)。用戶應該檢查函數返回值并采取適當的措施。
ptr =MemAlloc(pool); if(ptr ==NULL) { MemErrOutOfMemory(pool); } /* use memory via ptr */ MemFree(pool, ptr);
使用實時內核時,我們可以通過擴展內存分配函數,進一步避免丟失檢查和失敗處理的風險,使用阻塞等待空閑內存:
ptr =MemAllocWait(pool); /* use memory via ptr */ MemFree(pool, ptr); ptr =MemAllocWait(pool);
通過阻塞等待方式確保返回的指針是一個有效的內存塊。強制性安全任務監視器將檢測任務是否在定義的截止時間內獲得足夠的內存。
3內存釋放到錯誤內存池
如果用戶負責將內存釋放到正確的內存池中(例如,內存池是釋放內存的參數),可能會出錯。我們可以通過向info區域添加額外的參數來避免這個錯誤。為了簡單(快速)地訪問這些數據,info區作為已分配內存的一部分。應用程序不能使用這部分數據,并且位于應用程序內存塊引用的前面:
改進后的內存使用順序如下:
ptr =MemAllocWait(pool); /* use memory via ptr */ MemFree(ptr);
4空閑內存丟失
所謂的“內存泄漏”發生在內存分配且被使用之后,但沒有釋放內存塊的時候。此錯誤不容易檢測,特別是當分配和釋放操作將在不同的函數(或任務)中實現時。
在不知道應用程序細節的情況下,檢測內存泄漏的一種方法是使用內存看門狗,看門狗的工作方式類似于通常使用的執行看門狗。
假設在內存分配過程中定義了一個看門狗時間,這迫使我們在這段時間內觸發看門狗,以保持內存塊有效。
我們將內存計時數據存儲在info區域中。
為了檢查所有分配的內存塊的看門狗時間周期,我們引入了一個檢查函數。下列偽代碼可以幫助了解我們如何檢查內存塊。
voidMemCheck(pool) { foreach'block'in'pool'do: if('block::timeout'isgreater than0) then: decrement'block::timeout'by1 if('block::timeout'isequal to0) then: callMemErrTimeout(block) }
我們系統安全自檢過程中定期調用這個函數。使用序列如下所示。
ptr =MemAllocWait(timeout, pool); MemUseTrigger(ptr); /*use memory via ptr*/ MemFree(ptr);
如果錯過了看門狗時間周期,我們可以在回調函數中執行適當的動作:
voidMemErrTimeout(ptr) { /* action on timeout: */ /* log diagnostic data */ /* initiate safe state */ }
5內存多次釋放
當在沒有檢測機制的情況下多次(錯誤地)釋放一個內存塊時,可能導致正在運行系統的奇怪行為。這種錯誤很難調試,必須避免。
在info區域中添加一個額外的冗余值,可以非常有效地處理這個問題。推薦使用內存池參數的補值,需在內存分配函數中將這兩個值設置為匹配的一對。
內存釋放函數可以檢查這些冗余信息,將內存塊放回相應的內存池中,然后破壞冗余信息。實現偽代碼如下:
voidMemFree(ptr) { if('ptr::pool'isequal to complement of'ptr::inv_pool') then: release memory block'ptr'to'ptr::pool' set'ptr::inv_pool'to'ptr::pool' else: callMemErrDoubleFree(ptr) }
最后,我們可以在回調函數中為這種錯誤情況定義適當的操作:MemErrDoubleFree(ptr)。
6釋放后繼續使用內存
這個編程錯誤聽起來不可思議,但在多任務環境中,這個錯誤可能存在,在最壞的情況下,很長一段時間都沒有被發現。
為了檢測這種情況,我們可以重用info區域中的數據冗余。在這種情況下,我們在使用內存塊之前檢查冗余是否損壞。為了使代碼順序盡可能簡單,我們可以集成內存看門狗觸發:
voidMemStartAccess(ptr) { if('ptr::pool'is not equal to complement of'ptr::inv_pool') then: callMemErrUsedFree(ptr) else set'ptr::timeout'to'ptr::watchdog_time' }
最后,在回調函數MemErrUsedFree(ptr)中為這種錯誤情況定義適當的操作。
在使用內存塊之前,該檢測機制將需要一個額外的函數調用。
ptr =MemAllocWait(timeout, pool); MemStartAccess(ptr); /* use memory block via ptr */ MemFree(ptr);
7使用時釋放內存
這個編程錯誤與前面的錯誤屬于同一類。在多任務環境中,可能釋放了被中斷任務占用的內存塊。該任務重新運行時,其使用的內存已經被釋放。
針對這個問題,我們可以使用一個對稱函數的解決方案。對應MemStartAccess()函數,引入結束函數。這個新函數可以通知用戶內存塊不能使用了:
void MemEndAccess (ptr);
通過相應的阻塞函數來釋放內存,我們可以避免這類編程錯誤。
void MemFreeWait (ptr);
對應的動態內存使用序列如下:
ptr =MemAllocWait(timeout, pool); MemStartAccess(ptr); /*use memory block via ptr*/ MemEndAccess(ptr); MemFreeWait(ptr);
總結
在本文中,我們發現了一種在IEC61508系統中使用動態內存的方法,避免相應的編程錯誤并在檢測到錯誤后做出響應。我們為這些安全功能付出了相應的代價:每個分配的內存塊將占用額外內存空間,消耗了CPU運行時間。
盡管如此,還是建議在安全關鍵型系統中謹慎使用動態內存。
Flexible Safety RTOS是基于μC/OS-II+MPU機制實現的功能安全操作系統,提供了基于塊的內存管理機制。麥
-
函數
+關注
關注
3文章
4371瀏覽量
64229 -
動態內存
+關注
關注
1文章
25瀏覽量
8085 -
靜態內存
+關注
關注
0文章
6瀏覽量
1451
原文標題:IEC61508系統中的動態內存使用
文章出處:【微信號:麥克泰技術,微信公眾號:麥克泰技術】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
動態內存管理模塊的設計原理與實現

瑞薩電子功能安全IEC61508解決方案介紹(2)

請問使用動態內存分配安全嗎?
使用動態內存分配安全嗎
動態內存分配是什么意思
動態內存管理在面向嵌入式實時系統中的研究
基于IEC61508開發功能安全的處理器詳細介紹

嵌入式中需要用到動態內存嗎
Xilinx為IEC61508和ISO26262認證的安全應用降低風險并提高效率

瑞薩基于IEC61508的功能安全解決方案介紹(1)

評論