malloc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "malloc.h"
  5. #ifdef MEMWATCH
  6. #include "memwatch.h"
  7. #endif
  8. // 独自メモリマネージャを使用する場合、次のコメントを外してください。
  9. // #define USE_MEMMGR
  10. #if !defined(DMALLOC) && !defined(GCOLLECT) && !defined(BCHECK) && !defined(USE_MEMMGR)
  11. void* aMalloc_( size_t size, const char *file, int line, const char *func )
  12. {
  13. void *ret;
  14. // printf("%s:%d: in func %s: malloc %d\n",file,line,func,size);
  15. #ifdef MEMWATCH
  16. ret=mwMalloc(size,file,line);
  17. #else
  18. ret=malloc(size);
  19. #endif
  20. if(ret==NULL){
  21. printf("%s:%d: in func %s: malloc error out of memory!\n",file,line,func);
  22. exit(1);
  23. }
  24. return ret;
  25. }
  26. void* aCalloc_( size_t num, size_t size, const char *file, int line, const char *func )
  27. {
  28. void *ret;
  29. // printf("%s:%d: in func %s: calloc %d %d\n",file,line,func,num,size);
  30. #ifdef MEMWATCH
  31. ret=mwCalloc(num,size,file,line);
  32. #else
  33. ret=calloc(num,size);
  34. #endif
  35. if(ret==NULL){
  36. printf("%s:%d: in func %s: calloc error out of memory!\n",file,line,func);
  37. exit(1);
  38. }
  39. return ret;
  40. }
  41. void* aRealloc_( void *p, size_t size, const char *file, int line, const char *func )
  42. {
  43. void *ret;
  44. // printf("%s:%d: in func %s: realloc %p %d\n",file,line,func,p,size);
  45. #ifdef MEMWATCH
  46. ret=mwRealloc(p,size,file,line);
  47. #else
  48. ret=realloc(p,size);
  49. #endif
  50. if(ret==NULL){
  51. printf("%s:%d: in func %s: realloc error out of memory!\n",file,line,func);
  52. exit(1);
  53. }
  54. return ret;
  55. }
  56. char* aStrdup_( const void *p, const char *file, int line, const char *func )
  57. {
  58. char *ret;
  59. // printf("%s:%d: in func %s: strdup %p\n",file,line,func,p);
  60. #ifdef MEMWATCH
  61. ret=mwStrdup(p,file,line);
  62. #else
  63. ret= strdup((char *) p);
  64. #endif
  65. if(ret==NULL){
  66. printf("%s:%d: in func %s: strdup error out of memory!\n",file,line,func);
  67. exit(1);
  68. }
  69. return ret;
  70. }
  71. void aFree_( void *p, const char *file, int line, const char *func )
  72. {
  73. // printf("%s:%d: in func %s: free %p\n",file,line,func,p);
  74. #ifdef MEMWATCH
  75. mwFree(p,file,line);
  76. #else
  77. free(p);
  78. #endif
  79. }
  80. #elif defined(GCOLLECT)
  81. void * _bcallocA(size_t size, size_t cnt) {
  82. void *ret = aMallocA(size * cnt);
  83. memset(ret, 0, size * cnt);
  84. return ret;
  85. }
  86. void * _bcalloc(size_t size, size_t cnt) {
  87. void *ret = aMalloc(size * cnt);
  88. memset(ret, 0, size * cnt);
  89. return ret;
  90. }
  91. char * _bstrdup(const char *chr) {
  92. int len = strlen(chr);
  93. char *ret = (char*)aMalloc(len + 1);
  94. strcpy(ret, chr);
  95. return ret;
  96. }
  97. #elif defined(USE_MEMMGR)
  98. /* USE_MEMMGR */
  99. /*
  100. * メモリマネージャ
  101. * malloc , free の処理を効率的に出来るようにしたもの。
  102. * 複雑な処理を行っているので、若干重くなるかもしれません。
  103. *
  104. * データ構造など(説明下手ですいません^^; )
  105. * ・メモリを複数の「ブロック」に分けて、さらにブロックを複数の「ユニット」
  106. * に分けています。ユニットのサイズは、1ブロックの容量を複数個に均等配分
  107. * したものです。たとえば、1ユニット32KBの場合、ブロック1つは32Byteのユ
  108. * ニットが、1024個集まって出来ていたり、64Byteのユニットが 512個集まって
  109. * 出来ていたりします。(padding,unit_head を除く)
  110. *
  111. * ・ユニット同士はリンクリスト(block_prev,block_next) でつながり、同じサイ
  112. * ズを持つユニット同士もリンクリスト(samesize_prev,samesize_nect) でつな
  113. * がっています。それにより、不要となったメモリの再利用が効率的に行えます。
  114. */
  115. /* ブロックに入るデータ量 */
  116. #define BLOCK_DATA_SIZE 80*1024
  117. /* 一度に確保するブロックの数。 */
  118. #define BLOCK_ALLOC 32
  119. /* ブロックのアライメント */
  120. #define BLOCK_ALIGNMENT 64
  121. /* ブロック */
  122. struct block {
  123. int block_no; /* ブロック番号 */
  124. struct block* block_prev; /* 前に確保した領域 */
  125. struct block* block_next; /* 次に確保した領域 */
  126. int samesize_no; /* 同じサイズの番号 */
  127. struct block* samesize_prev; /* 同じサイズの前の領域 */
  128. struct block* samesize_next; /* 同じサイズの次の領域 */
  129. int unit_size; /* ユニットのバイト数 0=未使用 */
  130. int unit_hash; /* ユニットのハッシュ */
  131. int unit_count; /* ユニットの数 */
  132. int unit_used; /* 使用済みユニット */
  133. char data[BLOCK_DATA_SIZE];
  134. };
  135. struct unit_head {
  136. struct block* block;
  137. int size;
  138. const char* file;
  139. int line;
  140. };
  141. static struct block* block_first = NULL;
  142. static struct block* block_last = NULL;
  143. static struct block* block_unused = NULL;
  144. /* ユニットへのハッシュ。80KB/64Byte = 1280個 */
  145. static struct block* unit_first[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 最初 */
  146. static struct block* unit_unfill[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 埋まってない */
  147. static struct block* unit_last[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 最後 */
  148. /* メモリを使い回せない領域用のデータ */
  149. struct unit_head_large {
  150. struct unit_head_large* prev;
  151. struct unit_head_large* next;
  152. struct unit_head unit_head;
  153. };
  154. static struct unit_head_large *unit_head_large_first = NULL;
  155. static struct block* block_malloc(void);
  156. static void block_free(struct block* p);
  157. static void memmgr_info(void);
  158. void* aMalloc_(size_t size, const char *file, int line, const char *func ) {
  159. int i;
  160. struct block *block;
  161. int size_hash = (size+BLOCK_ALIGNMENT-1) / BLOCK_ALIGNMENT;
  162. size = size_hash * BLOCK_ALIGNMENT; /* アライメントの倍数に切り上げ */
  163. if(size == 0) {
  164. return NULL;
  165. }
  166. /* ブロック長を超える領域の確保には、malloc() を用いる */
  167. /* その際、unit_head.block に NULL を代入して区別する */
  168. if(size > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
  169. #ifdef MEMWATCH
  170. struct unit_head_large* p = (struct unit_head_large*)mwMalloc(sizeof(struct unit_head_large) + size,file,line);
  171. #else
  172. struct unit_head_large* p = (struct unit_head_large*)malloc(sizeof(struct unit_head_large) + size);
  173. #endif
  174. if(p != NULL) {
  175. p->unit_head.block = NULL;
  176. p->unit_head.size = size;
  177. p->unit_head.file = file;
  178. p->unit_head.line = line;
  179. if(unit_head_large_first == NULL) {
  180. unit_head_large_first = p;
  181. p->next = NULL;
  182. p->prev = NULL;
  183. } else {
  184. unit_head_large_first->prev = p;
  185. p->prev = NULL;
  186. p->next = unit_head_large_first;
  187. unit_head_large_first = p;
  188. }
  189. return (char *)p + sizeof(struct unit_head_large);
  190. } else {
  191. printf("MEMMGR::memmgr_alloc failed.\n");
  192. exit(1);
  193. }
  194. }
  195. /* 同一サイズのブロックが確保されていない時、新たに確保する */
  196. if(unit_unfill[size_hash] == NULL) {
  197. block = block_malloc();
  198. if(unit_first[size_hash] == NULL) {
  199. /* 初回確保 */
  200. unit_first[size_hash] = block;
  201. unit_last[size_hash] = block;
  202. block->samesize_no = 0;
  203. block->samesize_prev = NULL;
  204. block->samesize_next = NULL;
  205. } else {
  206. /* 連結作業 */
  207. unit_last[size_hash]->samesize_next = block;
  208. block->samesize_no = unit_last[size_hash]->samesize_no + 1;
  209. block->samesize_prev = unit_last[size_hash];
  210. block->samesize_next = NULL;
  211. unit_last[size_hash] = block;
  212. }
  213. unit_unfill[size_hash] = block;
  214. block->unit_size = size + sizeof(struct unit_head);
  215. block->unit_count = BLOCK_DATA_SIZE / block->unit_size;
  216. block->unit_used = 0;
  217. block->unit_hash = size_hash;
  218. /* 未使用Flagを立てる */
  219. for(i=0;i<block->unit_count;i++) {
  220. ((struct unit_head*)(&block->data[block->unit_size * i]))->block = NULL;
  221. }
  222. }
  223. /* ユニット使用個数加算 */
  224. block = unit_unfill[size_hash];
  225. block->unit_used++;
  226. /* ユニット内を全て使い果たした */
  227. if(block->unit_count == block->unit_used) {
  228. do {
  229. unit_unfill[size_hash] = unit_unfill[size_hash]->samesize_next;
  230. } while(
  231. unit_unfill[size_hash] != NULL &&
  232. unit_unfill[size_hash]->unit_count == unit_unfill[size_hash]->unit_used
  233. );
  234. }
  235. /* ブロックの中の空きユニット捜索 */
  236. for(i=0;i<block->unit_count;i++) {
  237. struct unit_head *head = (struct unit_head*)(&block->data[block->unit_size * i]);
  238. if(head->block == NULL) {
  239. head->block = block;
  240. head->size = size;
  241. head->line = line;
  242. head->file = file;
  243. return (char *)head + sizeof(struct unit_head);
  244. }
  245. }
  246. // ここに来てはいけない。
  247. printf("MEMMGR::memmgr_malloc() serious error.\n");
  248. memmgr_info();
  249. exit(1);
  250. return NULL;
  251. };
  252. void* aCalloc_(size_t num, size_t size, const char *file, int line, const char *func ) {
  253. void *p = aMalloc_(num * size,file,line,func);
  254. memset(p,0,num * size);
  255. return p;
  256. }
  257. void* aRealloc_(void *memblock, size_t size, const char *file, int line, const char *func ) {
  258. size_t old_size;
  259. if(memblock == NULL) {
  260. return aMalloc_(size,file,line,func);
  261. }
  262. old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head)))->size;
  263. if(old_size > size) {
  264. // サイズ縮小 -> そのまま返す(手抜き)
  265. return memblock;
  266. } else {
  267. // サイズ拡大
  268. void *p = aMalloc_(size,file,line,func);
  269. if(p != NULL) {
  270. memcpy(p,memblock,old_size);
  271. }
  272. aFree_(memblock,file,line,func);
  273. return p;
  274. }
  275. }
  276. void* aStrdup_(const void* string, const char *file, int line, const char *func ) {
  277. if(string == NULL) {
  278. return NULL;
  279. } else {
  280. int len = strlen(string);
  281. char *p = (char *)aMalloc_(len + 1,file,line,func);
  282. memcpy(p,string,len+1);
  283. return p;
  284. }
  285. }
  286. void aFree_(void *ptr, const char *file, int line, const char *func ) {
  287. struct unit_head *head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head));
  288. if(ptr == NULL) {
  289. return;
  290. } else if(head->block == NULL && head->size > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
  291. /* malloc() で直に確保された領域 */
  292. struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large));
  293. if(head_large->prev) {
  294. head_large->prev->next = head_large->next;
  295. } else {
  296. unit_head_large_first = head_large->next;
  297. }
  298. if(head_large->next) {
  299. head_large->next->prev = head_large->prev;
  300. }
  301. free(head_large);
  302. return;
  303. } else {
  304. /* ユニット解放 */
  305. struct block *block = head->block;
  306. if(head->block == NULL) {
  307. printf("memmgr: args of aFree is freed pointer %s line %d\n",file,line);
  308. } else {
  309. head->block = NULL;
  310. if(--block->unit_used == 0) {
  311. /* ブロックの解放 */
  312. if(unit_unfill[block->unit_hash] == block) {
  313. /* 空きユニットに指定されている */
  314. do {
  315. unit_unfill[block->unit_hash] = unit_unfill[block->unit_hash]->samesize_next;
  316. } while(
  317. unit_unfill[block->unit_hash] != NULL &&
  318. unit_unfill[block->unit_hash]->unit_count == unit_unfill[block->unit_hash]->unit_used
  319. );
  320. }
  321. if(block->samesize_prev == NULL && block->samesize_next == NULL) {
  322. /* 独立ブロックの解放 */
  323. unit_first[block->unit_hash] = NULL;
  324. unit_last[block->unit_hash] = NULL;
  325. unit_unfill[block->unit_hash] = NULL;
  326. } else if(block->samesize_prev == NULL) {
  327. /* 先頭ブロックの解放 */
  328. unit_first[block->unit_hash] = block->samesize_next;
  329. (block->samesize_next)->samesize_prev = NULL;
  330. } else if(block->samesize_next == NULL) {
  331. /* 末端ブロックの解放 */
  332. unit_last[block->unit_hash] = block->samesize_prev;
  333. (block->samesize_prev)->samesize_next = NULL;
  334. } else {
  335. /* 中間ブロックの解放 */
  336. (block->samesize_next)->samesize_prev = block->samesize_prev;
  337. (block->samesize_prev)->samesize_next = block->samesize_next;
  338. }
  339. block_free(block);
  340. } else {
  341. /* 空きユニットの再設定 */
  342. if(
  343. unit_unfill[block->unit_hash] == NULL ||
  344. unit_unfill[block->unit_hash]->samesize_no > block->samesize_no
  345. ) {
  346. unit_unfill[block->unit_hash] = block;
  347. }
  348. }
  349. }
  350. }
  351. }
  352. /* 現在の状況を表示する */
  353. static void memmgr_info(void) {
  354. int i;
  355. struct block *p;
  356. printf("** Memory Maneger Information **\n");
  357. if(block_first == NULL) {
  358. printf("Uninitialized.\n");
  359. return;
  360. }
  361. printf(
  362. "Blocks: %04u , BlockSize: %06u Byte , Used: %08uKB\n",
  363. block_last->block_no+1,sizeof(struct block),
  364. (block_last->block_no+1) * sizeof(struct block) / 1024
  365. );
  366. p = block_first;
  367. for(i=0;i<=block_last->block_no;i++) {
  368. printf(" Block #%04u : ",p->block_no);
  369. if(p->unit_size == 0) {
  370. printf("unused.\n");
  371. } else {
  372. printf(
  373. "size: %05u byte. used: %04u/%04u prev:",
  374. p->unit_size - sizeof(struct unit_head),p->unit_used,p->unit_count
  375. );
  376. if(p->samesize_prev == NULL) {
  377. printf("NULL");
  378. } else {
  379. printf("%04u",(p->samesize_prev)->block_no);
  380. }
  381. printf(" next:");
  382. if(p->samesize_next == NULL) {
  383. printf("NULL");
  384. } else {
  385. printf("%04u",(p->samesize_next)->block_no);
  386. }
  387. printf("\n");
  388. }
  389. p = p->block_next;
  390. }
  391. }
  392. /* ブロックを確保する */
  393. static struct block* block_malloc(void) {
  394. if(block_unused != NULL) {
  395. /* ブロック用の領域は確保済み */
  396. struct block* ret = block_unused;
  397. do {
  398. block_unused = block_unused->block_next;
  399. } while(block_unused != NULL && block_unused->unit_size != 0);
  400. return ret;
  401. } else {
  402. /* ブロック用の領域を新たに確保する */
  403. int i;
  404. int block_no;
  405. struct block* p = (struct block *)calloc(sizeof(struct block),BLOCK_ALLOC);
  406. if(p == NULL) {
  407. printf("MEMMGR::block_alloc failed.\n");
  408. exit(1);
  409. }
  410. if(block_first == NULL) {
  411. /* 初回確保 */
  412. block_no = 0;
  413. block_first = p;
  414. } else {
  415. block_no = block_last->block_no + 1;
  416. block_last->block_next = p;
  417. p->block_prev = block_last;
  418. }
  419. block_last = &p[BLOCK_ALLOC - 1];
  420. /* ブロックを連結させる */
  421. for(i=0;i<BLOCK_ALLOC;i++) {
  422. if(i != 0) {
  423. p[i].block_prev = &p[i-1];
  424. }
  425. if(i != BLOCK_ALLOC -1) {
  426. p[i].block_next = &p[i+1];
  427. }
  428. p[i].block_no = block_no + i;
  429. }
  430. /* 未使用ブロックへのポインタを更新 */
  431. block_unused = &p[1];
  432. p->unit_size = 1;
  433. return p;
  434. }
  435. }
  436. static void block_free(struct block* p) {
  437. /* free() せずに、未使用フラグを付けるだけ */
  438. p->unit_size = 0;
  439. /* 未使用ポインターを更新する */
  440. if(block_unused == NULL) {
  441. block_unused = p;
  442. } else if(block_unused->block_no > p->block_no) {
  443. block_unused = p;
  444. }
  445. }
  446. static char memmer_logfile[128];
  447. static FILE* memmgr_log(void) {
  448. FILE *fp = fopen(memmer_logfile,"w");
  449. if(!fp) { fp = stdout; }
  450. fprintf(fp,"memmgr: memory leaks found\n");
  451. return fp;
  452. }
  453. static void memmer_exit(void) {
  454. FILE *fp = NULL;
  455. int i;
  456. int count = 0;
  457. struct block *block = block_first;
  458. struct unit_head_large *large = unit_head_large_first;
  459. while(block) {
  460. if(block->unit_size) {
  461. if(!fp) { fp = memmgr_log(); }
  462. for(i=0;i<block->unit_count;i++) {
  463. struct unit_head *head = (struct unit_head*)(&block->data[block->unit_size * i]);
  464. if(head->block != NULL) {
  465. fprintf(
  466. fp,"%04d : %s line %d size %d\n",++count,
  467. head->file,head->line,head->size
  468. );
  469. }
  470. }
  471. }
  472. block = block->block_next;
  473. }
  474. while(large) {
  475. if(!fp) { fp = memmgr_log(); }
  476. fprintf(
  477. fp,"%04d : %s line %d size %d\n",++count,
  478. large->unit_head.file,
  479. large->unit_head.line,large->unit_head.size
  480. );
  481. large = large->next;
  482. }
  483. if(!fp) {
  484. printf("memmgr: no memory leaks found.\n");
  485. } else {
  486. printf("memmgr: memory leaks found.\n");
  487. fclose(fp);
  488. }
  489. }
  490. int do_init_memmgr(const char* file) {
  491. sprintf(memmer_logfile,"%s.log",file);
  492. atexit(memmer_exit);
  493. printf("memmgr: initialised: %s\n",memmer_logfile);
  494. return 0;
  495. }
  496. #endif