heap.inc 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team.
  4. functions for heap management in the data segment
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************}
  12. { Do not use standard memory manager }
  13. { Custom memory manager is Multi Threaded and does not require locking }
  14. { define HAS_MT_MEMORYMANAGER}
  15. { Do not use standard memory manager }
  16. { Custom memory manager requires locking when threading is used }
  17. { define HAS_MEMORYMANAGER}
  18. { Try to find the best matching block in general freelist }
  19. { define BESTMATCH}
  20. { DEBUG: Dump info when the heap needs to grow }
  21. { define DUMPGROW}
  22. { Memory profiling: at moment in time of max heap size usage,
  23. keep statistics of number of each size allocated
  24. (with 16 byte granularity) }
  25. { define DUMP_MEM_USAGE}
  26. {$ifdef HAS_MT_MEMORYMANAGER}
  27. {$define HAS_MEMORYMANAGER}
  28. {$endif HAS_MT_MEMORYMANAGER}
  29. {$ifdef DUMP_MEM_USAGE}
  30. {$define SHOW_MEM_USAGE}
  31. {$endif}
  32. const
  33. {$ifdef CPU64}
  34. blocksize = 32; { at least size of freerecord }
  35. blockshift = 5; { shr value for blocksize=2^blockshift}
  36. maxblocksize = 512+blocksize; { 1024+8 needed for heaprecord }
  37. {$else}
  38. blocksize = 16; { at least size of freerecord }
  39. blockshift = 4; { shr value for blocksize=2^blockshift}
  40. maxblocksize = 512+blocksize; { 1024+8 needed for heaprecord }
  41. {$endif}
  42. maxblockindex = maxblocksize div blocksize; { highest index in array of lists of memchunks }
  43. maxreusebigger = 8; { max reuse bigger tries }
  44. { common flags }
  45. fixedsizeflag = 1; { flag if the block is of fixed size }
  46. { memchunk var flags }
  47. usedflag = 2; { flag if the block is used or not }
  48. lastblockflag = 4; { flag if the block is the last in os chunk }
  49. firstblockflag = 8; { flag if the block is the first in os chunk }
  50. { os chunk flags }
  51. ocrecycleflag = 1;
  52. { above flags stored in size field }
  53. sizemask = not(blocksize-1);
  54. fixedoffsetshift = 16;
  55. fixedsizemask = sizemask and ((1 shl fixedoffsetshift) - 1);
  56. {****************************************************************************}
  57. {$ifdef DUMPGROW}
  58. {$define DUMPBLOCKS}
  59. {$endif}
  60. { Memory manager }
  61. const
  62. MemoryManager: TMemoryManager = (
  63. {$ifdef HAS_MT_MEMORYMANAGER}
  64. NeedLock: false;
  65. {$else HAS_MT_MEMORYMANAGER}
  66. NeedLock: true;
  67. {$endif HAS_MT_MEMORYMANAGER}
  68. GetMem: @SysGetMem;
  69. FreeMem: @SysFreeMem;
  70. FreeMemSize: @SysFreeMemSize;
  71. AllocMem: @SysAllocMem;
  72. ReAllocMem: @SysReAllocMem;
  73. MemSize: @SysMemSize;
  74. InitThread: nil;
  75. DoneThread: nil;
  76. RelocateHeap: nil;
  77. GetHeapStatus: @SysGetHeapStatus;
  78. GetFPCHeapStatus: @SysGetFPCHeapStatus;
  79. );
  80. {$ifndef HAS_MEMORYMANAGER}
  81. {
  82. We use 'fixed' size chunks for small allocations,
  83. and os chunks with variable sized blocks for big
  84. allocations.
  85. * a block is an area allocated by user
  86. * a chunk is a block plus our bookkeeping
  87. * an os chunk is a collection of chunks
  88. Memory layout:
  89. fixed: < chunk size > [ ... user data ... ]
  90. variable: < prev chunk size > < chunk size > [ ... user data ... ]
  91. When all chunks in an os chunk are free, we keep a few around
  92. but otherwise it will be freed to the OS.
  93. Fixed os chunks can be converted to variable os chunks and back
  94. (if not too big). To prevent repeated conversion overhead in case
  95. of user freeing/allocing same or a small set of sizes, we only do
  96. the conversion to the new fixed os chunk size format after we
  97. reuse the os chunk for another fixed size, or variable. Note that
  98. while the fixed size os chunk is on the freelists.oslist, it is also
  99. still present in a freelists.fixedlists, therefore we can easily remove
  100. the os chunk from the freelists.oslist if this size is needed again; we
  101. don't need to search freelists.oslist in alloc_oschunk, since it won't
  102. be present anymore if alloc_oschunk is reached. Note that removing
  103. from the freelists.oslist is not really done, only the recycleflag is
  104. set, allowing to reset the flag easily. alloc_oschunk will clean up
  105. the list while passing over it, that was a slow function anyway.
  106. }
  107. type
  108. pfreelists = ^tfreelists;
  109. poschunk = ^toschunk;
  110. toschunk = record
  111. size : ptrint;
  112. next : poschunk;
  113. used : ptrint;
  114. freelists : pfreelists;
  115. { padding inserted automatically by alloc_oschunk }
  116. end;
  117. ppmemchunk_fixed = ^pmemchunk_fixed;
  118. pmemchunk_fixed = ^tmemchunk_fixed;
  119. tmemchunk_fixed = record
  120. { aligning is done automatically in alloc_oschunk }
  121. size : ptrint;
  122. next_fixed,
  123. prev_fixed : pmemchunk_fixed;
  124. end;
  125. ppmemchunk_var = ^pmemchunk_var;
  126. pmemchunk_var = ^tmemchunk_var;
  127. tmemchunk_var = record
  128. prevsize : ptrint;
  129. freelists : pfreelists;
  130. size : ptrint;
  131. next_var,
  132. prev_var : pmemchunk_var;
  133. end;
  134. { ``header'', ie. size of structure valid when chunk is in use }
  135. { should correspond to tmemchunk_var_hdr structure starting with the
  136. last field. Reason is that the overlap is starting from the end of the
  137. record. }
  138. tmemchunk_fixed_hdr = record
  139. { aligning is done automatically in alloc_oschunk }
  140. size : ptrint;
  141. end;
  142. tmemchunk_var_hdr = record
  143. prevsize : ptrint;
  144. freelists : pfreelists;
  145. size : ptrint;
  146. end;
  147. pfpcheapstatus = ^tfpcheapstatus;
  148. tfixedfreelists = array[1..maxblockindex] of pmemchunk_fixed;
  149. tfreelists = record
  150. oslist : poschunk;
  151. oscount : dword;
  152. fixedlists : tfixedfreelists;
  153. varlist : pmemchunk_var;
  154. { chunks waiting to be freed from other thread }
  155. waitfixed : pmemchunk_fixed;
  156. lockfixed : trtlcriticalsection;
  157. waitvar : pmemchunk_var;
  158. lockvar : trtlcriticalsection;
  159. { heap statistics }
  160. internal_status : TFPCHeapStatus;
  161. end;
  162. const
  163. fixedfirstoffset = ((sizeof(toschunk) + sizeof(tmemchunk_fixed_hdr) + $f)
  164. and not $f) - sizeof(tmemchunk_fixed_hdr);
  165. varfirstoffset = ((sizeof(toschunk) + sizeof(tmemchunk_var_hdr) + $f)
  166. and not $f) - sizeof(tmemchunk_var_hdr);
  167. {$ifdef BESTMATCH}
  168. matcheffort = high(longint);
  169. {$else}
  170. matcheffort = 10;
  171. {$endif}
  172. var
  173. main_orig_freelists : pfreelists;
  174. main_relo_freelists : pfreelists;
  175. threadvar
  176. freelists : tfreelists;
  177. {$ifdef DUMP_MEM_USAGE}
  178. const
  179. sizeusageshift = 4;
  180. sizeusageindex = 2049;
  181. sizeusagesize = sizeusageindex shl sizeusageshift;
  182. type
  183. tsizeusagelist = array[0..sizeusageindex] of longint;
  184. threadvar
  185. sizeusage, maxsizeusage: tsizeusagelist;
  186. {$endif}
  187. {$endif HAS_MEMORYMANAGER}
  188. {*****************************************************************************
  189. Memory Manager
  190. *****************************************************************************}
  191. procedure GetMemoryManager(var MemMgr:TMemoryManager);
  192. begin
  193. MemMgr := MemoryManager;
  194. end;
  195. procedure SetMemoryManager(const MemMgr:TMemoryManager);
  196. begin
  197. MemoryManager := MemMgr;
  198. end;
  199. function IsMemoryManagerSet:Boolean;
  200. begin
  201. IsMemoryManagerSet := (MemoryManager.GetMem<>@SysGetMem)
  202. or (MemoryManager.FreeMem<>@SysFreeMem);
  203. end;
  204. procedure GetMem(Var p:pointer;Size:ptrint);
  205. begin
  206. p := MemoryManager.GetMem(Size);
  207. end;
  208. procedure GetMemory(Var p:pointer;Size:ptrint);
  209. begin
  210. GetMem(p,size);
  211. end;
  212. procedure FreeMem(p:pointer;Size:ptrint);
  213. begin
  214. MemoryManager.FreeMemSize(p,Size);
  215. end;
  216. procedure FreeMemory(p:pointer;Size:ptrint);
  217. begin
  218. FreeMem(p,size);
  219. end;
  220. function GetHeapStatus:THeapStatus;
  221. begin
  222. Result:=MemoryManager.GetHeapStatus();
  223. end;
  224. function GetFPCHeapStatus:TFPCHeapStatus;
  225. begin
  226. Result:=MemoryManager.GetFPCHeapStatus();
  227. end;
  228. function MemSize(p:pointer):ptrint;
  229. begin
  230. MemSize := MemoryManager.MemSize(p);
  231. end;
  232. { Delphi style }
  233. function FreeMem(p:pointer):ptrint;[Public,Alias:'FPC_FREEMEM_X'];
  234. begin
  235. FreeMem := MemoryManager.FreeMem(p);
  236. end;
  237. function FreeMemory(p:pointer):ptrint;
  238. begin
  239. FreeMemory := FreeMem(p);
  240. end;
  241. function GetMem(size:ptrint):pointer;
  242. begin
  243. GetMem := MemoryManager.GetMem(Size);
  244. end;
  245. function GetMemory(size:ptrint):pointer;
  246. begin
  247. GetMemory := GetMem(size);
  248. end;
  249. function AllocMem(Size:ptrint):pointer;
  250. begin
  251. AllocMem := MemoryManager.AllocMem(size);
  252. end;
  253. function ReAllocMem(var p:pointer;Size:ptrint):pointer;
  254. begin
  255. ReAllocMem := MemoryManager.ReAllocMem(p,size);
  256. end;
  257. function ReAllocMemory(var p:pointer;Size:ptrint):pointer;
  258. begin
  259. ReAllocMemory := ReAllocMem(p,size);
  260. end;
  261. { Needed for calls from Assembler }
  262. function fpc_getmem(size:ptrint):pointer;compilerproc;[public,alias:'FPC_GETMEM'];
  263. begin
  264. fpc_GetMem := MemoryManager.GetMem(size);
  265. end;
  266. procedure fpc_freemem(p:pointer);compilerproc;[public,alias:'FPC_FREEMEM'];
  267. begin
  268. MemoryManager.FreeMem(p);
  269. end;
  270. {$ifndef HAS_MEMORYMANAGER}
  271. {*****************************************************************************
  272. GetHeapStatus
  273. *****************************************************************************}
  274. function SysGetFPCHeapStatus:TFPCHeapStatus;
  275. var
  276. status: pfpcheapstatus;
  277. begin
  278. status := @freelists.internal_status;
  279. status^.CurrHeapFree := status^.CurrHeapSize - status^.CurrHeapUsed;
  280. result := status^;
  281. end;
  282. function SysGetHeapStatus :THeapStatus;
  283. var
  284. status: pfpcheapstatus;
  285. begin
  286. status := @freelists.internal_status;
  287. status^.CurrHeapFree := status^.CurrHeapSize - status^.CurrHeapUsed;
  288. result.TotalAllocated :=status^.CurrHeapUsed;
  289. result.TotalFree :=status^.CurrHeapFree;
  290. result.TotalAddrSpace :=status^.CurrHeapSize;
  291. result.TotalUncommitted :=0;
  292. result.TotalCommitted :=0;
  293. result.FreeSmall :=0;
  294. result.FreeBig :=0;
  295. result.Unused :=0;
  296. result.Overhead :=0;
  297. result.HeapErrorCode :=0;
  298. end;
  299. {$ifdef DUMPBLOCKS} // TODO
  300. procedure DumpBlocks(loc_freelists: pfreelists);
  301. var
  302. s,i,j : ptrint;
  303. hpfixed : pmemchunk_fixed;
  304. hpvar : pmemchunk_var;
  305. begin
  306. { fixed freelist }
  307. for i := 1 to maxblockindex do
  308. begin
  309. hpfixed := loc_freelists^.fixedlists[i];
  310. j := 0;
  311. while assigned(hpfixed) do
  312. begin
  313. inc(j);
  314. hpfixed := hpfixed^.next_fixed;
  315. end;
  316. writeln('Block ',i*blocksize,': ',j);
  317. end;
  318. { var freelist }
  319. hpvar := loc_freelists^.varlist;
  320. j := 0;
  321. s := 0;
  322. while assigned(hpvar) do
  323. begin
  324. inc(j);
  325. if hpvar^.size>s then
  326. s := hpvar^.size;
  327. hpvar := hpvar^.next_var;
  328. end;
  329. writeln('Variable: ',j,' maxsize: ',s);
  330. end;
  331. {$endif}
  332. {*****************************************************************************
  333. List adding/removal
  334. *****************************************************************************}
  335. procedure append_to_list_var(pmc: pmemchunk_var); inline;
  336. var
  337. varlist: ppmemchunk_var;
  338. begin
  339. varlist := @pmc^.freelists^.varlist;
  340. pmc^.prev_var := nil;
  341. pmc^.next_var := varlist^;
  342. if varlist^<>nil then
  343. varlist^^.prev_var := pmc;
  344. varlist^ := pmc;
  345. end;
  346. {$ifdef HEAP_DEBUG}
  347. function find_fixed_mc(loc_freelists: pfreelists; chunkindex: ptrint;
  348. pmc: pmemchunk_fixed): boolean;
  349. var
  350. pmc_temp: pmemchunk_fixed;
  351. begin
  352. pmc_temp := loc_freelists^.fixedlists[chunkindex];
  353. while pmc_temp <> nil do
  354. begin
  355. if pmc_temp = pmc then exit(true);
  356. pmc_temp := pmc_temp^.next_fixed;
  357. end;
  358. result := false;
  359. end;
  360. {$endif}
  361. procedure remove_from_list_fixed(pmc: pmemchunk_fixed; fixedlist: ppmemchunk_fixed); inline;
  362. begin
  363. if assigned(pmc^.next_fixed) then
  364. pmc^.next_fixed^.prev_fixed := pmc^.prev_fixed;
  365. if assigned(pmc^.prev_fixed) then
  366. pmc^.prev_fixed^.next_fixed := pmc^.next_fixed
  367. else
  368. fixedlist^ := pmc^.next_fixed;
  369. end;
  370. procedure remove_from_list_var(pmc: pmemchunk_var); inline;
  371. begin
  372. if assigned(pmc^.next_var) then
  373. pmc^.next_var^.prev_var := pmc^.prev_var;
  374. if assigned(pmc^.prev_var) then
  375. pmc^.prev_var^.next_var := pmc^.next_var
  376. else
  377. freelists.varlist := pmc^.next_var;
  378. end;
  379. procedure remove_all_from_list_fixed(chunksize: ptrint; poc: poschunk);
  380. var
  381. pmc, pmc_end: pmemchunk_fixed;
  382. fixedlist: ppmemchunk_fixed;
  383. begin
  384. pmc := pmemchunk_fixed(pointer(poc)+fixedfirstoffset);
  385. pmc_end := pmemchunk_fixed(pointer(poc)+(poc^.size and sizemask)-chunksize);
  386. fixedlist := @poc^.freelists^.fixedlists[chunksize shr blockshift];
  387. repeat
  388. remove_from_list_fixed(pmc, fixedlist);
  389. pmc := pointer(pmc)+chunksize;
  390. until pmc > pmc_end;
  391. end;
  392. procedure append_to_oslist(poc: poschunk; chunksize: ptrint);
  393. var
  394. pocsize: ptrint;
  395. loc_freelists: pfreelists;
  396. begin
  397. loc_freelists := poc^.freelists;
  398. { check if already on list }
  399. if (poc^.size and ocrecycleflag) <> 0 then
  400. begin
  401. inc(loc_freelists^.oscount);
  402. poc^.size := poc^.size and not ocrecycleflag;
  403. exit;
  404. end;
  405. { decide whether to free block or add to list }
  406. {$ifdef HAS_SYSOSFREE}
  407. pocsize := poc^.size and sizemask;
  408. if (loc_freelists^.oscount >= MaxKeptOSChunks) or
  409. (pocsize > growheapsize2) then
  410. begin
  411. if chunksize <> 0 then
  412. remove_all_from_list_fixed(chunksize, poc);
  413. dec(loc_freelists^.internal_status.currheapsize, pocsize);
  414. SysOSFree(poc, pocsize);
  415. end
  416. else
  417. begin
  418. {$endif}
  419. poc^.next := loc_freelists^.oslist;
  420. loc_freelists^.oslist := poc;
  421. inc(loc_freelists^.oscount);
  422. {$ifdef HAS_SYSOSFREE}
  423. end;
  424. {$endif}
  425. end;
  426. procedure clear_oschunk_on_freelist_fixed_flag(poc: poschunk); inline;
  427. { prevent thinking this os chunk is on the fixed freelists }
  428. begin
  429. pmemchunk_fixed(pointer(poc) + fixedfirstoffset)^.size := 0;
  430. end;
  431. procedure append_to_oslist_var(pmc: pmemchunk_var);
  432. var
  433. poc: poschunk;
  434. begin
  435. // block eligable for freeing
  436. poc := pointer(pmc)-varfirstoffset;
  437. remove_from_list_var(pmc);
  438. clear_oschunk_on_freelist_fixed_flag(poc);
  439. append_to_oslist(poc, 0);
  440. end;
  441. {*****************************************************************************
  442. Split block
  443. *****************************************************************************}
  444. function split_block(pcurr: pmemchunk_var; size: ptrint): pmemchunk_var;
  445. var
  446. pcurr_tmp : pmemchunk_var;
  447. sizeleft: ptrint;
  448. begin
  449. sizeleft := (pcurr^.size and sizemask)-size;
  450. if sizeleft>=sizeof(tmemchunk_var) then
  451. begin
  452. pcurr_tmp := pmemchunk_var(pointer(pcurr)+size);
  453. { update prevsize of block to the right }
  454. if (pcurr^.size and lastblockflag) = 0 then
  455. pmemchunk_var(pointer(pcurr)+(pcurr^.size and sizemask))^.prevsize := sizeleft;
  456. { inherit the lastblockflag }
  457. pcurr_tmp^.size := sizeleft or (pcurr^.size and lastblockflag);
  458. pcurr_tmp^.prevsize := size;
  459. pcurr_tmp^.freelists := pcurr^.freelists;
  460. { the block we return is not the last one anymore (there's now a block after it) }
  461. { decrease size of block to new size }
  462. pcurr^.size := size or (pcurr^.size and (not sizemask and not lastblockflag));
  463. { insert the block in the freelist }
  464. append_to_list_var(pcurr_tmp);
  465. result := pcurr_tmp;
  466. end
  467. else
  468. result := nil;
  469. end;
  470. {*****************************************************************************
  471. Try concat freerecords
  472. *****************************************************************************}
  473. procedure concat_two_blocks(mc_left, mc_right: pmemchunk_var);
  474. var
  475. mc_tmp : pmemchunk_var;
  476. size_right : ptrint;
  477. begin
  478. // mc_right can't be a fixed size block
  479. if mc_right^.size and fixedsizeflag<>0 then
  480. HandleError(204);
  481. // left block free, concat with right-block
  482. size_right := mc_right^.size and sizemask;
  483. inc(mc_left^.size, size_right);
  484. // if right-block was last block, copy flag
  485. if (mc_right^.size and lastblockflag) <> 0 then
  486. begin
  487. mc_left^.size := mc_left^.size or lastblockflag;
  488. end
  489. else
  490. begin
  491. // there is a block to the right of the right-block, adjust it's prevsize
  492. mc_tmp := pmemchunk_var(pointer(mc_right)+size_right);
  493. mc_tmp^.prevsize := mc_left^.size and sizemask;
  494. end;
  495. // remove right-block from doubly linked list
  496. remove_from_list_var(mc_right);
  497. end;
  498. procedure try_concat_free_chunk_forward(mc: pmemchunk_var);
  499. var
  500. mc_tmp : pmemchunk_var;
  501. begin
  502. { try concat forward }
  503. if (mc^.size and lastblockflag) = 0 then
  504. begin
  505. mc_tmp := pmemchunk_var(pointer(mc)+(mc^.size and sizemask));
  506. if (mc_tmp^.size and usedflag) = 0 then
  507. begin
  508. // next block free: concat
  509. concat_two_blocks(mc, mc_tmp);
  510. end;
  511. end;
  512. end;
  513. function try_concat_free_chunk(mc: pmemchunk_var): pmemchunk_var;
  514. var
  515. mc_tmp : pmemchunk_var;
  516. begin
  517. try_concat_free_chunk_forward(mc);
  518. { try concat backward }
  519. if (mc^.size and firstblockflag) = 0 then
  520. begin
  521. mc_tmp := pmemchunk_var(pointer(mc)-mc^.prevsize);
  522. if (mc_tmp^.size and usedflag) = 0 then
  523. begin
  524. // prior block free: concat
  525. concat_two_blocks(mc_tmp, mc);
  526. mc := mc_tmp;
  527. end;
  528. end;
  529. result := mc;
  530. end;
  531. {*****************************************************************************
  532. Grow Heap
  533. *****************************************************************************}
  534. function alloc_oschunk(loc_freelists: pfreelists; chunkindex, size: ptrint): pointer;
  535. var
  536. pmc,
  537. pmc_next : pmemchunk_fixed;
  538. pmcv : pmemchunk_var;
  539. poc : poschunk;
  540. prev_poc : poschunk;
  541. minsize,
  542. maxsize,
  543. i : ptrint;
  544. chunksize : ptrint;
  545. pocsize : ptrint;
  546. status : pfpcheapstatus;
  547. begin
  548. { increase size by size needed for os block header }
  549. minsize := size + varfirstoffset;
  550. { for fixed size chunks we keep offset from os chunk to mem chunk in
  551. upper bits, so maximum os chunk size is 64K on 32bit for fixed size }
  552. if chunkindex<>0 then
  553. maxsize := 1 shl (32-fixedoffsetshift)
  554. else
  555. maxsize := high(ptrint);
  556. { blocks available in freelist? }
  557. poc := loc_freelists^.oslist;
  558. prev_poc := nil;
  559. while poc <> nil do
  560. begin
  561. if (poc^.size and ocrecycleflag) <> 0 then
  562. begin
  563. { oops! we recycled this chunk; remove it from list }
  564. poc^.size := poc^.size and not ocrecycleflag;
  565. poc := poc^.next;
  566. if prev_poc = nil then
  567. loc_freelists^.oslist := poc
  568. else
  569. prev_poc^.next := poc;
  570. continue;
  571. end;
  572. pocsize := poc^.size and sizemask;
  573. if (pocsize >= minsize) and
  574. (pocsize <= maxsize) then
  575. begin
  576. size := pocsize;
  577. if prev_poc = nil then
  578. loc_freelists^.oslist := poc^.next
  579. else
  580. prev_poc^.next := poc^.next;
  581. dec(loc_freelists^.oscount);
  582. pmc := pmemchunk_fixed(pointer(poc)+fixedfirstoffset);
  583. if pmc^.size <> 0 then
  584. remove_all_from_list_fixed(pmc^.size and fixedsizemask, poc);
  585. break;
  586. end;
  587. prev_poc := poc;
  588. poc := poc^.next;
  589. end;
  590. if poc = nil then
  591. begin
  592. {$ifdef DUMPGROW}
  593. writeln('growheap(',size,') allocating ',(size+sizeof(toschunk)+$ffff) and not $ffff);
  594. DumpBlocks(loc_freelists);
  595. {$endif}
  596. { allocate by 64K size }
  597. size := (size+varfirstoffset+$ffff) and not $ffff;
  598. { allocate smaller blocks for fixed-size chunks }
  599. if chunkindex<>0 then
  600. begin
  601. poc := SysOSAlloc(GrowHeapSizeSmall);
  602. if poc<>nil then
  603. size := GrowHeapSizeSmall;
  604. end
  605. { first try 256K (default) }
  606. else if size<=GrowHeapSize1 then
  607. begin
  608. poc := SysOSAlloc(GrowHeapSize1);
  609. if poc<>nil then
  610. size := GrowHeapSize1;
  611. end
  612. { second try 1024K (default) }
  613. else if size<=GrowHeapSize2 then
  614. begin
  615. poc := SysOSAlloc(GrowHeapSize2);
  616. if poc<>nil then
  617. size := GrowHeapSize2;
  618. end
  619. { else allocate the needed bytes }
  620. else
  621. poc := SysOSAlloc(size);
  622. { try again }
  623. if poc=nil then
  624. begin
  625. poc := SysOSAlloc(size);
  626. if poc=nil then
  627. begin
  628. if ReturnNilIfGrowHeapFails then
  629. begin
  630. result := nil;
  631. exit
  632. end
  633. else
  634. HandleError(203);
  635. end;
  636. end;
  637. { prevent thinking this os chunk is on some freelist }
  638. clear_oschunk_on_freelist_fixed_flag(poc);
  639. poc^.next := nil;
  640. poc^.freelists := loc_freelists;
  641. { set the total new heap size }
  642. status := @loc_freelists^.internal_status;
  643. inc(status^.currheapsize, size);
  644. if status^.currheapsize > status^.maxheapsize then
  645. status^.maxheapsize := status^.currheapsize;
  646. end;
  647. { initialize os-block }
  648. poc^.used := 0;
  649. poc^.size := size;
  650. if chunkindex<>0 then
  651. begin
  652. { chop os chunk in fixedsize parts,
  653. maximum of $ffff elements are allowed, otherwise
  654. there will be an overflow }
  655. chunksize := chunkindex shl blockshift;
  656. if size-chunksize>maxsize then
  657. HandleError(204);
  658. { we need to align the user pointers to 8 byte at least for
  659. mmx/sse and doubles on sparc, align to 16 bytes }
  660. i := fixedfirstoffset;
  661. result := pointer(poc) + i;
  662. pmc := pmemchunk_fixed(result);
  663. pmc^.prev_fixed := nil;
  664. repeat
  665. pmc^.size := fixedsizeflag or chunksize or (i shl fixedoffsetshift);
  666. inc(i, chunksize);
  667. if i > size - chunksize then break;
  668. pmc_next := pmemchunk_fixed(pointer(pmc)+chunksize);
  669. pmc^.next_fixed := pmc_next;
  670. pmc_next^.prev_fixed := pmc;
  671. pmc := pmc_next;
  672. until false;
  673. pmc_next := loc_freelists^.fixedlists[chunkindex];
  674. pmc^.next_fixed := pmc_next;
  675. if pmc_next<>nil then
  676. pmc_next^.prev_fixed := pmc;
  677. loc_freelists^.fixedlists[chunkindex] := pmemchunk_fixed(result);
  678. end
  679. else
  680. begin
  681. { we need to align the user pointers to 8 byte at least for
  682. mmx/sse and doubles on sparc, align to 16 bytes }
  683. result := pointer(poc)+varfirstoffset;
  684. pmcv := pmemchunk_var(result);
  685. pmcv^.size := ((size-varfirstoffset) and sizemask) or (firstblockflag or lastblockflag);
  686. pmcv^.prevsize := 0;
  687. pmcv^.freelists := loc_freelists;
  688. append_to_list_var(pmcv);
  689. end;
  690. end;
  691. {*****************************************************************************
  692. SysGetMem
  693. *****************************************************************************}
  694. function finish_waitfixedlist(loc_freelists: pfreelists): boolean; forward;
  695. procedure finish_waitvarlist(loc_freelists: pfreelists); forward;
  696. function SysGetMem_Fixed(chunksize: ptrint): pointer;
  697. var
  698. pmc, pmc_next: pmemchunk_fixed;
  699. poc: poschunk;
  700. chunkindex: ptrint;
  701. loc_freelists: pfreelists;
  702. begin
  703. { try to find a block in one of the freelists per size }
  704. chunkindex := chunksize shr blockshift;
  705. loc_freelists := @freelists;
  706. pmc := loc_freelists^.fixedlists[chunkindex];
  707. { no free blocks ? }
  708. if assigned(pmc) then
  709. begin
  710. { remove oschunk from free list in case we recycle it }
  711. poc := poschunk(pointer(pmc) - (pmc^.size shr fixedoffsetshift));
  712. if poc^.used = 0 then
  713. begin
  714. poc^.size := poc^.size or ocrecycleflag;
  715. dec(loc_freelists^.oscount);
  716. end;
  717. end
  718. else if finish_waitfixedlist(loc_freelists) then
  719. { freed some to-be freed chunks, retry allocation }
  720. exit(SysGetMem_Fixed(chunksize))
  721. else
  722. begin
  723. pmc := alloc_oschunk(loc_freelists, chunkindex, chunksize);
  724. if not assigned(pmc) then
  725. exit(nil);
  726. poc := poschunk(pointer(pmc)-fixedfirstoffset);
  727. end;
  728. { get a pointer to the block we should return }
  729. result := pointer(pmc)+sizeof(tmemchunk_fixed_hdr);
  730. { update freelist }
  731. pmc_next := pmc^.next_fixed;
  732. loc_freelists^.fixedlists[chunkindex] := pmc_next;
  733. if assigned(pmc_next) then
  734. pmc_next^.prev_fixed := nil;
  735. inc(poc^.used);
  736. { statistics }
  737. with loc_freelists^.internal_status do
  738. begin
  739. inc(currheapused, chunksize);
  740. if currheapused > maxheapused then
  741. begin
  742. maxheapused := currheapused;
  743. {$ifdef DUMP_MEM_USAGE}
  744. maxsizeusage := sizeusage;
  745. {$endif}
  746. end;
  747. end;
  748. end;
  749. function SysGetMem_Var(size: ptrint): pointer;
  750. var
  751. pcurr : pmemchunk_var;
  752. pbest : pmemchunk_var;
  753. loc_freelists : pfreelists;
  754. iter : longint;
  755. begin
  756. result:=nil;
  757. { free pending items }
  758. loc_freelists := @freelists;
  759. finish_waitvarlist(loc_freelists);
  760. pbest := nil;
  761. pcurr := loc_freelists^.varlist;
  762. iter := high(longint);
  763. while assigned(pcurr) and (iter>0) do
  764. begin
  765. if (pcurr^.size>size) then
  766. begin
  767. if not assigned(pbest) or (pcurr^.size<pbest^.size) then
  768. begin
  769. pbest := pcurr;
  770. if pcurr^.size = size then
  771. break;
  772. end;
  773. iter := matcheffort;
  774. end;
  775. pcurr := pcurr^.next_var;
  776. dec(iter);
  777. end;
  778. pcurr := pbest;
  779. if not assigned(pcurr) then
  780. begin
  781. // all os-chunks full, allocate a new one
  782. pcurr := alloc_oschunk(loc_freelists, 0, size);
  783. if not assigned(pcurr) then
  784. exit;
  785. end;
  786. { get pointer of the block we should return }
  787. result := pointer(pcurr)+sizeof(tmemchunk_var_hdr);
  788. { remove the current block from the freelist }
  789. remove_from_list_var(pcurr);
  790. { create the left over freelist block, if at least 16 bytes are free }
  791. split_block(pcurr, size);
  792. { flag block as used }
  793. size := pcurr^.size and sizemask;
  794. pcurr^.size := pcurr^.size or usedflag;
  795. pcurr^.freelists := loc_freelists;
  796. { statistics }
  797. with loc_freelists^.internal_status do
  798. begin
  799. inc(currheapused, size);
  800. if currheapused > maxheapused then
  801. begin
  802. maxheapused := currheapused;
  803. {$ifdef DUMP_MEM_USAGE}
  804. maxsizeusage := sizeusage;
  805. {$endif}
  806. end;
  807. end;
  808. end;
  809. function SysGetMem(size : ptrint):pointer;
  810. begin
  811. { Something to allocate ? }
  812. if size<=0 then
  813. begin
  814. { give an error for < 0 }
  815. if size<0 then
  816. HandleError(204);
  817. { we always need to allocate something, using heapend is not possible,
  818. because heappend can be changed by growheap (PFV) }
  819. size := 1;
  820. end;
  821. { calc to multiple of 16 after adding the needed bytes for memchunk header }
  822. if size <= (maxblocksize - sizeof(tmemchunk_fixed_hdr)) then
  823. begin
  824. size := (size+(sizeof(tmemchunk_fixed_hdr)+(blocksize-1))) and fixedsizemask;
  825. result := sysgetmem_fixed(size);
  826. end
  827. else
  828. begin
  829. size := (size+(sizeof(tmemchunk_var_hdr)+(blocksize-1))) and sizemask;
  830. result := sysgetmem_var(size);
  831. end;
  832. {$ifdef DUMP_MEM_USAGE}
  833. size := sysmemsize(result);
  834. if size > sizeusagesize then
  835. inc(sizeusage[sizeusageindex])
  836. else
  837. inc(sizeusage[size shr sizeusageshift]);
  838. {$endif}
  839. end;
  840. {*****************************************************************************
  841. SysFreeMem
  842. *****************************************************************************}
  843. procedure waitfree_fixed(pmc: pmemchunk_fixed; loc_freelists: pfreelists);
  844. begin
  845. entercriticalsection(loc_freelists^.lockfixed);
  846. pmc^.next_fixed := loc_freelists^.waitfixed;
  847. loc_freelists^.waitfixed := pmc;
  848. leavecriticalsection(loc_freelists^.lockfixed);
  849. end;
  850. procedure waitfree_var(pmcv: pmemchunk_var; loc_freelists: pfreelists);
  851. begin
  852. entercriticalsection(loc_freelists^.lockvar);
  853. pmcv^.next_var := loc_freelists^.waitvar;
  854. loc_freelists^.waitvar := pmcv;
  855. leavecriticalsection(loc_freelists^.lockvar);
  856. end;
  857. function SysFreeMem_Fixed(pmc: pmemchunk_fixed): ptrint;
  858. var
  859. chunkindex,
  860. chunksize: ptrint;
  861. poc: poschunk;
  862. pmc_next: pmemchunk_fixed;
  863. loc_freelists: pfreelists;
  864. begin
  865. poc := poschunk(pointer(pmc)-(pmc^.size shr fixedoffsetshift));
  866. chunksize := pmc^.size and fixedsizemask;
  867. loc_freelists := @freelists;
  868. if loc_freelists <> poc^.freelists then
  869. begin
  870. if poc^.freelists = main_orig_freelists then
  871. poc^.freelists := main_relo_freelists;
  872. if loc_freelists <> poc^.freelists then
  873. begin
  874. { deallocated in wrong thread! add to to-be-freed list of correct thread }
  875. waitfree_fixed(pmc, poc^.freelists);
  876. exit(chunksize);
  877. end;
  878. end;
  879. dec(loc_freelists^.internal_status.currheapused, chunksize);
  880. { insert the block in it's freelist }
  881. chunkindex := chunksize shr blockshift;
  882. pmc_next := loc_freelists^.fixedlists[chunkindex];
  883. pmc^.prev_fixed := nil;
  884. pmc^.next_fixed := pmc_next;
  885. if assigned(pmc_next) then
  886. pmc_next^.prev_fixed := pmc;
  887. loc_freelists^.fixedlists[chunkindex] := pmc;
  888. { decrease used blocks count }
  889. dec(poc^.used);
  890. if poc^.used <= 0 then
  891. begin
  892. { decrease used blocks count }
  893. if poc^.used=-1 then
  894. HandleError(204);
  895. { osblock can be freed? }
  896. append_to_oslist(poc, chunksize);
  897. end;
  898. result := chunksize;
  899. end;
  900. function SysFreeMem_Var(pmcv: pmemchunk_var): ptrint;
  901. var
  902. chunksize: ptrint;
  903. loc_freelists: pfreelists;
  904. begin
  905. chunksize := pmcv^.size and sizemask;
  906. loc_freelists := @freelists;
  907. if loc_freelists <> pmcv^.freelists then
  908. begin
  909. if pmcv^.freelists = main_orig_freelists then
  910. pmcv^.freelists := main_relo_freelists;
  911. if loc_freelists <> pmcv^.freelists then
  912. begin
  913. { deallocated in wrong thread! add to to-be-freed list of correct thread }
  914. waitfree_var(pmcv, pmcv^.freelists);
  915. exit(chunksize);
  916. end;
  917. end;
  918. dec(loc_freelists^.internal_status.currheapused, chunksize);
  919. { insert the block in it's freelist }
  920. pmcv^.size := pmcv^.size and (not usedflag);
  921. append_to_list_var(pmcv);
  922. pmcv := try_concat_free_chunk(pmcv);
  923. if (pmcv^.size and (firstblockflag or lastblockflag)) = (firstblockflag or lastblockflag) then
  924. append_to_oslist_var(pmcv);
  925. result := chunksize;
  926. end;
  927. function SysFreeMem(p: pointer): ptrint;
  928. var
  929. pmc: pmemchunk_fixed;
  930. {$ifdef DUMP_MEM_USAGE}
  931. size: sizeint;
  932. {$endif}
  933. begin
  934. if p=nil then
  935. begin
  936. result:=0;
  937. exit;
  938. end;
  939. {$ifdef DUMP_MEM_USAGE}
  940. size := sysmemsize(p);
  941. if size > sizeusagesize then
  942. dec(sizeusage[sizeusageindex])
  943. else
  944. dec(sizeusage[size shr sizeusageshift]);
  945. {$endif}
  946. pmc := pmemchunk_fixed(p-sizeof(tmemchunk_fixed_hdr));
  947. { check if this is a fixed- or var-sized chunk }
  948. if (pmc^.size and fixedsizeflag) = 0 then
  949. result := sysfreemem_var(pmemchunk_var(p-sizeof(tmemchunk_var_hdr)))
  950. else
  951. result := sysfreemem_fixed(pmc);
  952. end;
  953. function finish_waitfixedlist(loc_freelists: pfreelists): boolean;
  954. { free to-be-freed chunks, return whether we freed anything }
  955. var
  956. pmc: pmemchunk_fixed;
  957. begin
  958. if loc_freelists^.waitfixed = nil then
  959. exit(false);
  960. entercriticalsection(loc_freelists^.lockfixed);
  961. while loc_freelists^.waitfixed <> nil do
  962. begin
  963. { keep next_fixed, might be destroyed }
  964. pmc := loc_freelists^.waitfixed;
  965. loc_freelists^.waitfixed := pmc^.next_fixed;
  966. SysFreeMem_Fixed(pmc);
  967. end;
  968. leavecriticalsection(loc_freelists^.lockfixed);
  969. result := true;
  970. end;
  971. procedure finish_waitvarlist(loc_freelists: pfreelists);
  972. { free to-be-freed chunks, return whether we freed anything }
  973. var
  974. pmcv: pmemchunk_var;
  975. begin
  976. loc_freelists := @freelists;
  977. if loc_freelists^.waitvar = nil then
  978. exit;
  979. entercriticalsection(loc_freelists^.lockvar);
  980. while loc_freelists^.waitvar <> nil do
  981. begin
  982. { keep next_var, might be destroyed }
  983. pmcv := loc_freelists^.waitvar;
  984. loc_freelists^.waitvar := pmcv^.next_var;
  985. SysFreeMem_Var(pmcv);
  986. end;
  987. leavecriticalsection(loc_freelists^.lockvar);
  988. end;
  989. {*****************************************************************************
  990. SysFreeMemSize
  991. *****************************************************************************}
  992. Function SysFreeMemSize(p: pointer; size: ptrint):ptrint;
  993. begin
  994. if size<=0 then
  995. begin
  996. if size<0 then
  997. HandleError(204);
  998. exit(0);
  999. end;
  1000. { can't free partial blocks, ignore size }
  1001. result := SysFreeMem(p);
  1002. end;
  1003. {*****************************************************************************
  1004. SysMemSize
  1005. *****************************************************************************}
  1006. function SysMemSize(p: pointer): ptrint;
  1007. begin
  1008. result := pmemchunk_fixed(pointer(p)-sizeof(tmemchunk_fixed_hdr))^.size;
  1009. if (result and fixedsizeflag) = 0 then
  1010. begin
  1011. result := result and sizemask;
  1012. dec(result, sizeof(tmemchunk_var_hdr));
  1013. end
  1014. else
  1015. begin
  1016. result := result and fixedsizemask;
  1017. dec(result, sizeof(tmemchunk_fixed_hdr));
  1018. end;
  1019. end;
  1020. {*****************************************************************************
  1021. SysAllocMem
  1022. *****************************************************************************}
  1023. function SysAllocMem(size: ptrint): pointer;
  1024. begin
  1025. result := MemoryManager.GetMem(size);
  1026. if result<>nil then
  1027. FillChar(result^,MemoryManager.MemSize(result),0);
  1028. end;
  1029. {*****************************************************************************
  1030. SysResizeMem
  1031. *****************************************************************************}
  1032. function SysTryResizeMem(var p: pointer; size: ptrint): boolean;
  1033. var
  1034. chunksize,
  1035. oldsize,
  1036. currsize : ptrint;
  1037. pcurr : pmemchunk_var;
  1038. pnext : pmemchunk_var;
  1039. begin
  1040. SysTryResizeMem := false;
  1041. { fix p to point to the heaprecord }
  1042. chunksize := pmemchunk_fixed(p-sizeof(tmemchunk_fixed_hdr))^.size;
  1043. { handle fixed memchuncks separate. Only allow resizes when the
  1044. new size fits in the same block }
  1045. if (chunksize and fixedsizeflag) <> 0 then
  1046. begin
  1047. currsize := chunksize and fixedsizemask;
  1048. { 1. Resizing to smaller sizes will never allocate a new block. We just keep the current block. This
  1049. is needed for the expectations that resizing to a small block will not move the contents of
  1050. a memory block
  1051. 2. For resizing to greater size first check if the size fits in the fixed block range to prevent
  1052. "truncating" the size by the fixedsizemask }
  1053. if ((size <= (maxblocksize - sizeof(tmemchunk_fixed_hdr))) and
  1054. ((size+sizeof(tmemchunk_fixed_hdr)+(blocksize-1)) and sizemask <= currsize)) then
  1055. begin
  1056. systryresizemem:=true;
  1057. exit;
  1058. end;
  1059. { we need to allocate a new fixed or var memchunck }
  1060. exit;
  1061. end;
  1062. { var memchunk }
  1063. { do not fragment the heap with small shrinked blocks }
  1064. { also solves problem with var sized chunks smaller than sizeof(tmemchunk_var) }
  1065. if size < maxblocksize div 2 then
  1066. exit(false);
  1067. currsize := chunksize and sizemask;
  1068. size := (size+sizeof(tmemchunk_var_hdr)+(blocksize-1)) and sizemask;
  1069. { is the allocated block still correct? }
  1070. if (currsize>=size) and (size>(currsize-blocksize)) then
  1071. begin
  1072. SysTryResizeMem := true;
  1073. exit;
  1074. end;
  1075. { get pointer to block }
  1076. pcurr := pmemchunk_var(pointer(p)-sizeof(tmemchunk_var_hdr));
  1077. oldsize := currsize;
  1078. { do we need to allocate more memory ? }
  1079. if size>currsize then
  1080. begin
  1081. { the size is bigger than the previous size, we need to allocated more mem.
  1082. We first check if the blocks after the current block are free. If not then we
  1083. simply call getmem/freemem to get the new block }
  1084. pnext:=pmemchunk_var(pointer(pcurr)+currsize);
  1085. if ((pnext^.size and usedflag) = 0)
  1086. and ((pnext^.size and sizemask) > size-currsize) then
  1087. begin
  1088. concat_two_blocks(pcurr,pnext);
  1089. currsize := pcurr^.size and sizemask;
  1090. end
  1091. else
  1092. exit;
  1093. end;
  1094. { is the size smaller then we can adjust the block to that size and insert
  1095. the other part into the freelist }
  1096. if currsize>size then
  1097. begin
  1098. pnext := split_block(pcurr, size);
  1099. currsize := pcurr^.size and sizemask;
  1100. if pnext <> nil then
  1101. try_concat_free_chunk_forward(pnext);
  1102. end;
  1103. with freelists.internal_status do
  1104. begin
  1105. inc(currheapused, currsize-oldsize);
  1106. if currheapused > maxheapused then
  1107. maxheapused := currheapused;
  1108. end;
  1109. SysTryResizeMem := true;
  1110. end;
  1111. {*****************************************************************************
  1112. SysResizeMem
  1113. *****************************************************************************}
  1114. function SysReAllocMem(var p: pointer; size: ptrint):pointer;
  1115. var
  1116. newsize,
  1117. oldsize,
  1118. minsize : ptrint;
  1119. p2 : pointer;
  1120. begin
  1121. { Free block? }
  1122. if size=0 then
  1123. begin
  1124. if p<>nil then
  1125. begin
  1126. MemoryManager.FreeMem(p);
  1127. p := nil;
  1128. end;
  1129. end
  1130. else
  1131. { Allocate a new block? }
  1132. if p=nil then
  1133. begin
  1134. p := MemoryManager.GetMem(size);
  1135. end
  1136. else
  1137. begin
  1138. { Resize block }
  1139. {$ifdef DUMP_MEM_USAGE}
  1140. oldsize:=SysMemSize(p);
  1141. {$endif}
  1142. if not SysTryResizeMem(p,size) then
  1143. begin
  1144. oldsize:=MemoryManager.MemSize(p);
  1145. { Grow with bigger steps to prevent the need for
  1146. multiple getmem/freemem calls for fixed blocks. It might cost a bit
  1147. of extra memory, but in most cases a reallocmem is done multiple times. }
  1148. if oldsize<maxblocksize then
  1149. begin
  1150. newsize:=oldsize*2+blocksize;
  1151. if size>newsize then
  1152. newsize:=size;
  1153. end
  1154. else
  1155. newsize:=size;
  1156. { calc size of data to move }
  1157. minsize:=oldsize;
  1158. if newsize < minsize then
  1159. minsize := newsize;
  1160. p2 := MemoryManager.GetMem(newsize);
  1161. if p2<>nil then
  1162. Move(p^,p2^,minsize);
  1163. MemoryManager.FreeMem(p);
  1164. p := p2;
  1165. {$ifdef DUMP_MEM_USAGE}
  1166. end else begin
  1167. size := sysmemsize(p);
  1168. if size <> oldsize then
  1169. begin
  1170. if oldsize > sizeusagesize then
  1171. dec(sizeusage[sizeusageindex])
  1172. else if oldsize >= 0 then
  1173. dec(sizeusage[oldsize shr sizeusageshift]);
  1174. if size > sizeusagesize then
  1175. inc(sizeusage[sizeusageindex])
  1176. else if size >= 0 then
  1177. inc(sizeusage[size shr sizeusageshift]);
  1178. end;
  1179. {$endif}
  1180. end;
  1181. end;
  1182. SysReAllocMem := p;
  1183. end;
  1184. {$endif HAS_MEMORYMANAGER}
  1185. {$ifndef HAS_MEMORYMANAGER}
  1186. {*****************************************************************************
  1187. InitHeap
  1188. *****************************************************************************}
  1189. {$if not(defined(gba)) and not(defined(nds))}
  1190. { This function will initialize the Heap manager and need to be called from
  1191. the initialization of the system unit }
  1192. procedure InitHeapThread;
  1193. var
  1194. loc_freelists: pfreelists;
  1195. begin
  1196. loc_freelists := @freelists;
  1197. fillchar(loc_freelists^,sizeof(tfreelists),0);
  1198. initcriticalsection(loc_freelists^.lockfixed);
  1199. initcriticalsection(loc_freelists^.lockvar);
  1200. {$ifdef DUMP_MEM_USAGE}
  1201. fillchar(sizeusage,sizeof(sizeusage),0);
  1202. fillchar(maxsizeusage,sizeof(sizeusage),0);
  1203. {$endif}
  1204. end;
  1205. procedure InitHeap;
  1206. var
  1207. loc_freelists: pfreelists;
  1208. begin
  1209. { we cannot initialize the locks here yet, thread support is
  1210. not loaded yet }
  1211. loc_freelists := @freelists;
  1212. fillchar(loc_freelists^,sizeof(tfreelists),0);
  1213. { main freelist will be copied in memory }
  1214. main_orig_freelists := loc_freelists;
  1215. end;
  1216. {$endif}
  1217. procedure RelocateHeap;
  1218. var
  1219. loc_freelists: pfreelists;
  1220. begin
  1221. { this function should be called in main thread context }
  1222. loc_freelists := @freelists;
  1223. main_relo_freelists := loc_freelists;
  1224. initcriticalsection(loc_freelists^.lockfixed);
  1225. initcriticalsection(loc_freelists^.lockvar);
  1226. if MemoryManager.RelocateHeap <> nil then
  1227. MemoryManager.RelocateHeap();
  1228. end;
  1229. procedure FinalizeHeap;
  1230. var
  1231. poc : poschunk;
  1232. i : longint;
  1233. loc_freelists: pfreelists;
  1234. begin
  1235. loc_freelists := @freelists;
  1236. finish_waitfixedlist(loc_freelists);
  1237. finish_waitvarlist(loc_freelists);
  1238. if main_relo_freelists <> nil then
  1239. begin
  1240. donecriticalsection(loc_freelists^.lockfixed);
  1241. donecriticalsection(loc_freelists^.lockvar);
  1242. end;
  1243. {$ifdef SHOW_MEM_USAGE}
  1244. writeln('Max heap used/size: ', loc_freelists^.internal_status.maxheapused, '/',
  1245. loc_freelists^.internal_status.maxheapsize);
  1246. flush(output);
  1247. {$endif}
  1248. {$ifdef DUMP_MEM_USAGE}
  1249. for i := 0 to sizeusageindex-1 do
  1250. if maxsizeusage[i] <> 0 then
  1251. writeln('size ', i shl sizeusageshift, ' usage ', maxsizeusage[i]);
  1252. writeln('size >', sizeusagesize, ' usage ', maxsizeusage[sizeusageindex]);
  1253. flush(output);
  1254. {$endif}
  1255. {$ifdef HAS_SYSOSFREE}
  1256. while assigned(loc_freelists^.oslist) do
  1257. begin
  1258. poc:=loc_freelists^.oslist^.next;
  1259. SysOSFree(loc_freelists^.oslist, loc_freelists^.oslist^.size and sizemask);
  1260. dec(loc_freelists^.oscount);
  1261. loc_freelists^.oslist:=poc;
  1262. end;
  1263. {$endif HAS_SYSOSFREE}
  1264. end;
  1265. {$endif HAS_MEMORYMANAGER}