/** * @file kc_memory.h * @brief KC メモリ管理モジュール * @copyright 2003 - 2023 Nomura Kei * @depends * kc.h * kc_memory_mark.h * kc_memory_entry.h * kc_memory_listener.h * * 利用例) * #include <kc_memory.h> * int main(void) * { * // プログラム終了時に発生しているメモリリーク情報を出力します。 * // 引数が true の場合、メモリ確保/解放情報を出力します。 * KcMemory_start(true); * ...(省略)... * return 0; * } */ #ifndef KC_MEMORY_H #define KC_MEMORY_H #include <stdlib.h> #include <kc.h> #include <kc_memory_mark.h> #include <kc_memory_entry.h> #include <kc_memory_listener.h> #include <kc_threads.h> #ifdef __cplusplus extern "C" { namespace kc { using namespace std; #endif // ============================================================================= // KcMemoryManager // ============================================================================= /** メモリ管理で扱うバッファサイズ */ #define KC_MEMORY_MAX_BUFFER_SIZE (4096) /** * メモリ管理を開始します。 * * 本関数を実行することで、次の動作が実施されます。 * (1) メモリ確保失敗時に、エラー情報を出力します。 * (2) プログラム終了時に、解放されていないメモリを出力します。 * (3) detail が true の場合、メモリ確保/解放時に出力します。 * ※出力先は、いずれも stderr となります。 * * @param detail true/false (メモリ確保/解放の情報を出力する/出力しない) */ void KcMemory_start(bool detail); /** * 現在確保去れているメモリ一覧を出力します。 */ void KcMemory_dump(void); /** * メモリの確保、解放を管理します。 */ typedef struct KcMemoryManager_ { /** * メモリ確保、解放、エラー発生時に通知するためのリスナを登録します。 * @code * 例) * void Listener_allocate(const KcMemoryEntry* entry) { * printf("メモリ確保! : %s:%d\n", entry->file, entry->line); * } * void Listener_free(const KcMemoryEntry* entry) { * printf("メモリ解放! : %s:%d\n", entry->file, entry->line); * } * void Listener_error(const KcMemoryEntry* entry, const char* msg) { * printf("エラー! : %s", msg); * } * * int main (void) { * KcMemoryListener listener = { * .allocate = Listener_allocate, * .free = Listener_free, * .error = Listener_error * }; * kc_memory_manager->set_listener(&listener); * ...(省略)... * return 0; * } * @endcode * * @param listener 登録するリスナ * @return true/false (リスナ登録成功/リスナ登録失敗) */ bool (*set_listener)(KcMemoryListener *listener); /** * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 * ハンドラの戻りが false の場合、呼び出しを終了します。 * * @param handler ハンドラ * @param info ハンドラの第二引数に渡される付加情報 * @return true/false (実行成功/実行失敗) */ bool (*entries)(bool (*handler)(const KcMemoryEntry *entry, void *info), void *info); /** * 管理しているメモリエントリを引数に指定されたハンドラを実行します。 * ハンドラの戻り値が true の場合、該当するメモリを解放します。 * new で確保されたメモリが解放される際、デストラクタは呼び出されないため注意が必要です。 * * @param handler ハンドラ * @param info ハンドラの第二引数に渡される付加情報 * @return true 固定 */ bool (*freeif)(bool (*handler)(const KcMemoryEntry *entry, void *info), void *info); /** * 管理しているメモリ情報のダンプデータを引数に指定されたハンドラを実行します。 * * @param handler ハンドラ * @param byte ダンプするバイト数 * @param binary true の場合、バイナリの16進数表現がダンプデータに追加されます。 * @param ascii true の場合、ASCIIがダンプデータに追加されます。 * @param column カラム数 */ void (*dump)(bool (*handler)(const char *data), int bytes, bool binary, bool ascii, int column); /** * 指定されたサイズのメモリを確保します。 * * @param size 確保するメモリサイズ * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ void *(*malloc)(size_t size, const char *file, const char *func, int line); /** * アライメント指定付きで、指定されたサイズのメモリを確保します。 * * @param alignment アライメント * @param size 確保するメモリサイズ * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ void *(*aligned_alloc)(size_t alignment, size_t size, const char *file, const char *func, int line); /** * 指定されたサイズの nmemb 個の要素からなるメモリを確保します。 * 確保したメモリ領域の内容は、0x00 で初期化されます。 * * @param nmemb 確保するメモリ要素数 * @param size 1要素あたりのメモリサイズ * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ void *(*calloc)(size_t nmemb, size_t size, const char *file, const char *func, int line); /** * 指定されたポインタが指すメモリサイズを変更します。 * * @param ptr メモリサイズを変更するポインタ * @param size 変更後のメモリサイズ * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ void *(*realloc)(void *ptr, size_t size, const char *file, const char *func, int line); /** * 指定されたメモリを解放します。 * * @param ptr 解放するメモリへのポインタ */ void (*free)(void *ptr); // ========================================================================= // 内部利用関数 // ========================================================================= /** * [内部利用関数] * KcMemoryManager を初期化します。 * 本関数は、KcMemoryManager の各関数が実行される際に呼び出され、 * 一度だけ初期化処理を実施します。 */ void (*_init)(void); bool (*_add)(KcMemoryEntry *entry); bool (*_remove)(KcMemoryEntry *entry); void *(*_allocate)(size_t alignment, size_t size, KcMemoryMark mark, const char *file, const char *func, int line); void *(*_reallocate)(void *ptr, size_t size, KcMemoryMark mark, const char *file, const char *func, int line); void *(*_reallocate_managed_ptr)(void *ptr, size_t size, KcMemoryMark mark, const char *file, const char *func, int line); void (*_deallocate)(void *ptr); // ========================================================================= // 内部利用変数 // ========================================================================= KcMemoryListener _listener; //!< リスナ KcMemoryEntry _head; //!< 管理メモリの先頭 KcMemoryEntry _tail; //!< 管理メモリの末尾 KcMemoryEntry _error; //!< エラー発生時一時利用 char _tmpbuf[KC_MEMORY_MAX_BUFFER_SIZE]; //!< 一時利用のためのバッファ mtx_t *_mutex; //!< 同期実行利用のための Mutex } KcMemoryManager; /** * KcMemoryManager の唯一のインスタンス。 */ extern KcMemoryManager *const kc_memory_manager; /** * stdlib.h の malloc * * @param size 確保するメモリサイズ * @return メモリへのポインタ */ void *raw_malloc(size_t size); /** * stdlib.h の aligned_alloc * windows の場合、本関数で獲得したメモリは、_aligned_free で解放してください。 * * @param alignment アライメント * @param size 確保するメモリサイズ * @return メモリへのポインタ */ void *raw_aligned_alloc(size_t alignment, size_t size); /** * stdlib.h の calloc * * @param nmemb 個数 * @param size 要素のサイズ * @return メモリへのポインタ */ void *raw_calloc(size_t nmemb, size_t size); /** * stdlib.h の realloc * * @param ptr 再確保するためのメモリへのポインタ * @param size 確保するメモリサイズ * @return メモリへのポインタ */ void *raw_realloc(void *ptr, size_t size); /** * stdlib.h の free * * @param ptr 解放するメモリへのポインタ */ void raw_free(void *ptr); #ifdef KC_MEMORY_ENABLED #define malloc(size) kc_memory_manager->malloc(size, __FILE__, __func__, __LINE__) #define aligned_alloc(alignment, size) kc_memory_manager->aligned_alloc(alignment, size, __FILE__, __func__, __LINE__) #define calloc(nmemb, size) kc_memory_manager->calloc(nmemb, size, __FILE__, __func__, __LINE__) #define realloc(ptr, size) kc_memory_manager->realloc(ptr, size, __FILE__, __func__, __LINE__) #define free(ptr) kc_memory_manager->free(ptr) #endif #ifdef __cplusplus } // namespace kc } // extern "C" #endif #endif // KC_MEMORY_H