Allocate a byte array and free it afterwards in delphi - delphi

I would like to allocate space (dynamic size) with a byte array and get a pointer to the "spacearea" and free it later if I don't need it anymore.
I know about VirtualAlloc, VirutalAllocEx and LocalAlloc.
Which one is the best and how can I free the memory afterwards?
Thank you for your help.

I don't think it is a good idea to use the winapi for that instead of the native Pascal functions.
You can simply define an array of bytes as
var yourarray: array of byte;
then it can be allocated by
setlength(yourarray, yoursize);
and freed by
setlength(yourarray, 0);
Such an array is reference counted and you can access individual bytes as yourarray[byteid]
Or if you really want pointers, you can use:
var p: pointer;
GetMem(p, yoursize);
FreeMem(p);

You should better use GetMem/FreeMem or a dynamic array, or a RawByteString. Note that GetMem/FreeMem, dynamic arrays or RawByteString uses the heap, not the stack for its allocation.
There is no interest about using VirtualAlloc/VirtualFree instead of GetMem/FreeMem. For big blocks, the memory manager (which implements the heap) will call VirtualAlloc/VirtualFree APIs, but for smaller blocks, it will be more optimized to rely on the heap.
Since VirtualAlloc/VirtualFree is local to the current process, the only interest to use it is if you want to create some memory block able to execute code, e.g. for creating some stubbing wrappers of classes or interfaces, via their VirtualAllocEx/VirtualFreeEx APIs (but I doubt it is your need).
If you want to use some memory global to all processes/programs, you have GlobalAlloc/GlobalFree API calls at hand.

VirtualAlloc is a page allocation function. It is the low level user space code function for allocating memory. But you must understand that the memory returned from VirtualAlloc is aligned to a multiple of the page size.
On windows 32 bit the page size is normally 4096 Bytes. On other systems it might be larger.
So this makes VirtualAlloc useful when you need whole pages of memory. VirtualAlloc can allocate large "ranges of pages". The pages are virtual and are thus actually mappings to underlying system RAM and half the time are swapped out to the swap file, and this is why it is called VirtualAlloc, emphasis on virtual.
Using VirtualAlloc and VirtualAllocEx you can also just reserve some pages of memory. Reserved pages are a range that are held in reserved state until you are sure they will be used, at which point you can commit the pages, at which time the underlying resources needed for the pages will be allocated/committed.
Use VirtualFree to free the pages you allocated or reserved with VirtualAlloc.
The difference between VirtualAlloc and LocalAlloc is that LocalAlloc allocates from a heap, and a heap is a mechanism of allocating blocks of memory from much larger blocks of reserved pages. Internally, a heap allocates large sections of memory using VirtualAlloc, and then divides those pages up into smaller blocks that you see as buffers returned from functions like malloc, getmem and LocalAlloc.
LocalAlloc could be though of as the Windows built in version of malloc or getmem. A call to LocalAlloc is similar to calling malloc in C++ or to calling getmem in Delphi. In fact you could override the GetMem in Delphi and use LocalAlloc and your DElphi application will probably just run the same.
Call LocalFree to free some memory allocated with LocalAlloc. Internally this will mark the block of memory as available to the next caller.
So the main consideration now when deciding is on overhead. If you need to allocate often then you should use LocalAlloc or getmem, because committing and reserving virtual pages is a more time consuming process.
In other words, use getmem or LocalAlloc unless you have a very special reason not to.
In all my tests with Delphi 5 versus C++ compilers the Delphi 5 getmem was faster, although that was five years ago. Since then allocators like hoard are available that might be faster. But it is hard to say what is faster when there are so many variables.
But for sure all the heap functions like LocalAlloc, malloc and getmem should be much faster than allocating and freeing with VirtualAlloc, which is normally used to reserve memory internally for heap functions like LocalAlloc and getmem.
For Pascal programs, prefer getmem or SetLength because this is more portable. Or you can write your own wrapper function to LocalAlloc or whatever the OS heap function is.

The functions that you have listed are WinAPI functions, which are platform dependant. Obviously you should use the functions of the same API for deallocating that you have used for allocation.
If you want to use Delphi memory manager, than GetMemory and FreeMemory is the obvious choice, however if you need your pointer to be aligned to the system page size(which is requirement for some low level libraries) or you are going to use large buffer sizes, then Windows API virtual memory functions VirtualAlloc and VirtualFree are your best friends.

Related

Can i give mapped memory to malloc?

Say I have a big block of mapped memory I finished using. It came from mmaping anonymous memory or using MAP_PRIVATE. I could munmap it, then have malloc mmap again the next time I make a big enough allocation.
Could I instead give the memory to malloc directly? Could I say "Hey malloc, here's an address range I mapped. Go use it for heap space. Feel free to mprotect, mremap, or even munmap it as you wish."?
I'm using glibc on linux.
glibc malloc calls __morecore (a function pointer) to obtain more memory. See <malloc.h>. However, this will not work in general because the implementation assumes that the function behaves like sbrk and returns memory from a single, larger memory region. In practice, with glibc malloc, the only realistic way to make memory available for reuse by malloc is calling munmap.
Other malloc implementations allow donating memory (in some cases as internal interfaces). For example, musl's malloc has a function called __malloc_donate which should do what you are asking for.

Why does OCaml need to create its own heaps for garbage collection?

According to this OCaml's memory is contained in two contiguous chunks of virtual memory managed by the OCaml runtime. I would like to know why this is necessary. Couldn't OCaml simply use the system malloc to allocate memory, and only use these heaps to store the block headers and pointers to the object's actual home in memory? This seems like a reinvention of the wheel when the operating system can do so much of the work instead.
I would also like to know why OCaml must allocate an entirely new major heap during the compact phase of garbage collection (source here), e.g.:
In the following rough sketch, let the letters A-D represent equally-sized pieces of OCaml blocks, and let . represent a freed space of the same size. From what I am given to understand, the OCaml garbage collector would "compact" this major heap:
[AAABB..CCCCCC.....DDD....]
By allocating a new major heap:
[.........................]
And copying the still-live blocks into it, before freeing the original heap:
[AAABBCCCCCCDDD...........]
How is this more efficient than simply rearranging those blocks inside the original heap? In the example above, a contiguity check could have avoided having to move blocks A and B at all, and in any case, how is it more efficient to ask the operating system to always allocate an entire new major heap?
Every garbage collector handle their own heap for performance reasons. malloc is a quite slow, and compared to OCaml minor heap allocation it is multiple orders of magnitude slower (an allocation in the minor heap is done in 2 assembly instructions).
For the compaction, no that doesn't reallocate.

how does malloc work in details?

I am trying to find some useful information on the malloc function.
when I call this function it allocates memory dynamically. it returns the pointer (e.g. the address) to the beginning of the allocated memory.
the questions:
how the returned address is used in order to read/write into the allocated memory block (using inderect addressing registers or how?)
if it is not possible to allocate a block of memory it returns NULL. what is NULL in terms of hardware?
in order to allocate memory in heap we need to know which memory parts are occupied. where this information (about the occupied memory) is stored (if for example we use a small risc microcontroller)?
Q3 The usual way that heaps are managed are through a linked list. In the simplest case, the malloc function retains a pointer to the first free-space block in the heap, and each free-space block has a header that points to the next free space block in the heap. So the heap is in-effect self-defining in terms of knowing what is not occupied (and by inference what is therefore occupied); this minimizes the amount of overhead RAM needed to manage the heap.
When new space is needed via a malloc call, a large enough free-space block is found by traversing the linked list. That found free-space block is given to the malloc caller (with a small hidden header), and if needed a smaller free-space block is inserted into the linked list with any residual space between the original free space block and how much memory the malloc call asked for.
When a heap block is released by the application, its block is just formatted with the linked-list header, and added to the linked list, usually with some extra logic to combine consecutive free-space blocks into one larger free-space block.
Debugging versions of malloc usually do more, including retaining linked-lists of the allocated areas too, "guard zones" around the allocated heap areas to help detect memory overflows, etc. These take up extra heap space (making the heap effectively smaller in terms of usable space for the applications), but are extremely helpful when debugging.
Q2 A NULL pointer is effectively just a zero, which if used attempts to access memory starting at location 0 of RAM, which is almost always reserved memory of the OS. This is the cause of a significant quantity of memory violation aborts, all caused by programmer's lack of error checking for NULL returns from functions that allocate memory).
Because accessing memory location 0 by a non-OS application is never what is wanted, most hardware aborts any attempt to access location 0 by non-OS software. Even with page mapping such that the applications memory space (including location 0) is never mapped to real RAM location 0, since NULL is always zero, most CPUs will still abort attempts to access location 0 on the assumption that this is an access via a pointer that contains NULL.
Given your RISC processor, you will need to read its documentation to see how it handles attempts to access memory location 0.
Q1 There are many high-level language ways to use allocated memory, primarily through pointers, strings, and arrays.
In terms of assembly language and the hardware itself, the allocated heap block address just gets put into a register that is being used for memory indirection. You will need to see how that is handled in the RISC processor. However if you use C or C++ or such higher level language, then you don't need to worry about registers; the compiler handles all that.
Since you are using malloc, can we assume you are using C?
If so, you assign the result to a pointer variable, then you can access the memory by referencing through the variable. You don't really know how this is implemented in assembly. That depends on CPU you are using. malloc return 0 if it fails. Since usually NULL is defined as 0, you can test for NULL. You don't care how malloc tracks the free memory. If you really need this information, you should look at the source in glibc/malloc available on the net
char * c = malloc(10); // allocate 10 bytes
if (c == NULL)
// handle error case
else
*c = 'a' // write a in the first character on the block

Does FastMM support reserving virtual memory and calling in chunks to grow an array?

I know I can reserve virtual memory using VirtualAlloc.
e.g. I can claim 1GB of virtual memory and then call in the first MB of that to put my a growing array into.
When the array grows beyond 1MB I call in the 2nd MB and so on.
This way I don't need to move the array around in memory when it grows, it just stays in place and the Intel/AMD virtual memory manager takes care of my problems.
However does FastMM support this structure, so I don't have to do my own memory management?
Pseudo code:
type
PBigarray = ^TBigarray;
TBigArray = array[0..0] of SomeRecord;
....
begin
VirtualMem:= FastMM.ReserveVirtualMemory(1GB);
PBigArray:= FastMM.ClaimPhysicalMemory(VirtualMem, 1MB);
....
procedure GrowBigArray
begin
FastMM.ClaimMorePhysicalMemory(PBigArray, 1MB {extra});
//will generate OOM exception when claim exceeds 1GB
Does FastMM support this?
No, FastMM4 (as of the latest version I looked at) does not explicitly support this. It's really not a functionality you would expect in a general purpose memory manager as it's trivially simple to do with VirtualAlloc calls.
NexusMM4 (which is part of NexusDB) does something that gives you a similar result, but without wasting all the address space before it is needed in the background.
If you make an initial large allocation (directly via GetMem, or indirectly via a dynamic array or such) the memory is allocated in just the size needed, via VirtualAlloc.
But if that allocation is then resized to a larger size, NexusMM will use a different way to allocate memory which allows it to simply unmap the allocation from the address space an remap it again, at a larger size, when further reallocs takes place.
This prevents the 2 major problems that most general purpose memory managers have when reallocating:
during a normal realloc the existing and new allocation need to be present in the address space at the same time, temporarily doubling the address space and physical memory requirements
during a normal realloc, the whole contents of the existing allocation needs to be copied
So with NexusMM you would get all the advantages of what you showed in your pseudo code (with the exception that the first realloc will involve a copy, and that growing your array might change it's address) by simply using normal GetMem/ReallocMem/FreeMem calls.

How can I find the size of the memory referenced by a pointer?

GetMem allows you to allocate a buffer of arbitrary size. Somewhere, the size information is retained by the memory manager, because you don't need to tell it how big the buffer is when you pass the pointer to FreeMem.
Is that information for internal use only, or is there any way to retrieve the size of the buffer pointed to by a pointer?
It would seem that the size of a block referenced by a pointer returned by GetMem() must be available from somewhere, given that FreeMem() does not require that you identify the size of memory to be freed - the system must be able to determine that, so why not the application developer?
But, as others have said, the precise details of the memory management involved are NOT defined by the system per se.... Delphi has always had a replaceable memory manager architecture, and the "interface" defined for compatible memory managers does not require that they provide this information for an arbitrary pointer.
The default memory manager will maintain the necessary information in whatever way suits it, but some other memory manager will almost certainly use an entirely different, if superficially similar, mechanism, so even if you hack a solution based on intimate knowledge of one memory manager, if you change the memory manager (or if it is changed for you, e.g. by a change in thesystem defined, memory manager which you perhaps are using by default, as occurred between Delphi 2005 and 2006, for example) then your solution will almost certainly break.
In general, it's not an unreasonable assumption on the part of the RTL/memory manager that the application should already know how big a piece of memory a GetMem() allocated pointer refers to, given that the application asked for it in the first place! :)
And if your application did NOT allocate the pointer then your application's memory manager has absolutely no way of knowing how big the block it references may be. It may be a pointer into the middle of some larger block, for example - only the source of the pointer can possibly know how it relates to the memory it references!
But, if your application really does need to maintain such information about it's own pointers, then it could of course easily devise a means to achieve this with a simple singleton class or function library through which GetMem()/FreeMem() requests are routed, to maintain a record of the associated requested size for each current allocated pointer. Such a mechanism could then of course easily expose this information as required, entirely reliably and independently of whatever memory manager is in use.
This may in face be the only option if an "accurate" record is required , as a given memory manager implementation may allocate a larger block of memory for a given size of data than is actually requested. I do not know if any memory manager does in fact do this, but it could do so in theory, for efficiency sake.
It is for internal use as it depends on the MemoryManager used. BTW, that's why you need to use the pair GetMem/FreeMem from the same MemoryManager; there is no canonical way of knowing how the memory has been reserved.
In Delphi, if you look at FastMM4, you can see that the memory is allocated in small, medium or large blocks:
the small blocks are allocated in pools of fixed size blocks (block size is defined at the pool level in the block type)
TSmallBlockType = packed record
{True = Block type is locked}
BlockTypeLocked: Boolean;
{Bitmap indicating which of the first 8 medium block groups contain blocks
of a suitable size for a block pool.}
AllowedGroupsForBlockPoolBitmap: byte;
{The block size for this block type}
BlockSize: Word;
the medium blocks are also allocated in pools but have a variable size
{Medium block layout:
Offset: -8 = Previous Block Size (only if the previous block is free)
Offset: -4 = This block size and flags
Offset: 0 = User data / Previous Free Block (if this block is free)
Offset: 4 = Next Free Block (if this block is free)
Offset: BlockSize - 8 = Size of this block (if this block is free)
Offset: BlockSize - 4 = Size of the next block and flags
{Get the block header}
LBlockHeader := PCardinal(Cardinal(APointer) - BlockHeaderSize)^;
{Get the medium block size}
LBlockSize := LBlockHeader and DropMediumAndLargeFlagsMask;
the large blocks are allocated individually with the required size
TLargeBlockHeader = packed record
{Points to the previous and next large blocks. This circular linked
list is used to track memory leaks on program shutdown.}
PreviousLargeBlockHeader: PLargeBlockHeader;
NextLargeBlockHeader: PLargeBlockHeader;
{The user allocated size of the Large block}
UserAllocatedSize: Cardinal;
{The size of this block plus the flags}
BlockSizeAndFlags: Cardinal;
end;
Is that information for internal use only, or is there any way to retrieve the size of the buffer pointed to by a pointer?
Do these two `alternatives' contradict each other?
It's for internal use only.
There is some information before the allocated area to store meta information. This means, each time you allocate a piece of memory, a bigger piece is allocated and the first bytes are used for meta information. The returned pointer is to the block following this meta information.
I can imagine that the format is changed with an other version of the memory manager so don't count on this.
That information is for internal use only.
Note that memory managers doesn't need to store the size as part of the memory returned, many memory managers will store it in an internal table and use the memory address of the start of the chunk given out as a lookup key in that table.

Resources