heap.inc 40 KB

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