There is a maximum number of pointers that can be allocated? I'm working on a function that allocates various pointers to various records. After an amount (x) not calculated, the AllocMem function allocates a pointer overwriting the existing pointers. Anyone have a tips?
function NewObject(ID: Integer): boolean;
Var P: PNewObject;
begin
P:= Allocmem(SizeOf(TNewObject));
P^.ID:= ID;
...
Pointers that were allocated will only be released when the program close!
There is no maximum number of pointers that can be allocated. Dynamic memory allocation may fail if the memory manager is unable to find a suitable block of memory. In that scenario EOutOfMemory is raised.
After an amount (x) not calculated, the AllocMem function allocates a pointer overwriting the existing pointers.
No, that is not the case. The dynamic memory allocation functions will never return a block of memory that is already in use.
It sounds as though your program allocates but never deallocates. That might be a tenable approach if you have a garbage collector at hand, but this is not the case for you. Perhaps you need to consider deallocating when you are done with the memory.
Related
As a follow-up to a previous answer to another question, I became curious of how heap allocations work in a loop.
Take the following two scenarios for example:
Declaration:
SomeList: TObjectList<TSomething>;
Scenario 1:
begin
for X := 1 to 10 do
SomeList[X].DoSomething;
end;
Scenario 2:
var
S: TSomething;
begin
for X:= 1 to 10 do begin
S:= SomeList[X];
S.DoSomething;
end;
end;
Now what I'm curious about is how heap allocations work in either scenario. Scenario 1 is directly calling the list item in each loop iteration, which I'm wondering if it adds to the heap and releases for each time the loop iterates. The second scenario on the other hand, obviously has one heap allocation, by simply declaring a local variable.
What I'm wondering is which scenario performs the heavier load on heap allocation (as being one leading cause to performance issues)?
Now what I'm curious about is how heap allocations work in either scenario.
There are no heap allocations in your example (unless DoSomething() is allocating memory internally).
Scenario 1 is directly calling the list item in each loop iteration
So is Scenario 2.
I'm wondering if it adds to the heap and releases for each time the loop iterates.
Nothing is being added to the heap.
The second scenario on the other hand, obviously has one heap allocation, by simply declaring a local variable.
Local variables are allocated on the stack, not on the heap. Variables can point at memory on the heap, though. Your S variable in Scenario 2 does, because TObject-derived classes are always allocated on the heap. S is just a local variable on the stack that points at the heap memory occupied by the TSomething object.
What I'm wondering is which scenario performs the heavier load on heap allocation (as being one leading cause to performance issues)?
Neither, because there is no heap allocation in your example.
Here I have a few lines of delphi code running in delphi 7:
var
ptr:Pointer ;
begin
ptr:=AllocMem(40);
ptr:=Pchar('OneNationUnderGod');
if ptr<>nil then
FreeMem(ptr);
end;
Upon running this code snippet, FreeMem(ptr)will raise an error:'invalid pointer operation'. If I delete the sentence:
ptr:=Pchar('OneNationUnderGod');
then no error will occur. Now I have two questions,
1.Why is this happening? 2. If I have to use the Pchar sentence, how should I free the memory allocated earlier?
Much appreciation for your help!
The problem is that you are modifying the address held in the variable ptr.
You call AllocMem to allocate a buffer, which you refer to using ptr. That much is fine. But you must never change the value of ptr, the address of the buffer. And you do change it.
You wrote:
ptr:=AllocMem(40);
ptr:=Pchar('OneNationUnderGod');
The second line is the problem. You have modified ptr and now ptr refers to something else (a string literal held in read-only memory as it happens). You have now lost track of the buffer allocated by your call to AllocMem. You asked AllocMem for a new block of memory and then immediately discarded that block of memory.
What you presumably mean to do is to copy the string. Perhaps like this:
ptr := AllocMem(40);
StrCopy(ptr, 'OneNationUnderGod');
Now we are fine to call FreeMem, because ptr still contains the address that the call to AllocMem provided.
ptr := AllocMem(40);
try
StrCpy(ptr, 'OneNationUnderGod');
// do stuff with ptr
finally
FreeMem(ptr);
end;
Clearly in real code you would find a better and more robust way to specify buffer lengths than a hard-coded value.
In your code, assuming the above fix is applied, the test for ptr being nil is needless. AllocMem never returns nil. Failure of AllocMem results in an exception being raised.
Having said all that, it's not usual to operate on string buffers in this way. It is normal to use Delphi strings. If you need a PChar, for instance to use with interop, make one with PChar(str) where str is of type string.
You say that you must use dynamically allocated PChar buffers. Perhaps that is so, but I very much doubt it.
It crashes because you are freeing static memory that was not dynamically allocated. There is no need to free memory used by literals at all. Only free memory that is dynamically allocated.
I'd try to make what you've done more explicit. You seem to mistake the name of a variable with its value. However actually - considering values - what you did was
ptrA:=AllocMem(40);
ptrB:=Pchar('OneNationUnderGod');
if ptrB<>nil then
FreeMem(ptrB);
Every new assignment changes the value overwriting the previous one, thus you freeing another pointer that was allocated.
You may read documentation for functions like StrNew, StrDispose, StrCopy, StrLCopy and sample codes with those to see some patterns of working with PChar strings.
Let's go back to the basics. Frankly, I have never used New and Dispose functions before. However, after I read the New() documentation and the included examples on the Embarcadero Technologies's website and the Delphi Basics explanation of New(), it leaves questions in my head:
What are the advantages of using System.New() instead of a local variable, other than just spare a tiny amount of memory?
Common code examples for New() are more or less as follows:
var
pCustRec : ^TCustomer;
begin
New(pCustRec);
pCustRec^.Name := 'Her indoors';
pCustRec^.Age := 55;
Dispose(pCustRec);
end;
In what circumstances is the above code more appropriate than the code below?
var
CustRec : TCustomer;
begin
CustRec.Name := 'Her indoors';
CustRec.Age := 55;
end;
If you can use a local variable, do so. That's a rule with practically no exceptions. This results in the cleanest and most efficient code.
If you need to allocate on the heap, use dynamic arrays, GetMem or New. Use New when allocating a record.
Examples of being unable to use the stack include structures whose size are not known at compile time, or very large structures. But for records, which are the primary use case for New, these concerns seldom apply.
So, if you are faced with a choice of stack vs heap for a record, invariably the stack is the correct choice.
From a different perspective:
Both can suffer from buffer overflow and can be exploited.
If a local variable overflows, you get stack corruption.
If a heap variable overflows, you get heap corruption.
Some say that stack corruptions are easier to exploit than heap corruptions, but that is not true in general.
Note there are various mechanisms in operating systems, processor architectures, libraries and languages that try to help preventing these kinds of exploits.
For instance there is DEP (Data Execution Prevention), ASLR (Address Space Layout Randomization) and more are mentioned at Wikipedia.
A local static variable reserves space on the limited stack. Allocated memory is located on the heap, which is basically all memory available.
As mentioned, the stack space is limited, so you should avoid large local variables and also large parameters which are passed by value (absence of var/const in the parameter declaration).
A word on memory usage:
1. Simple types (integer, char, string, double etc.) are located directly on the stack. The amount of bytes used can be determined by the sizeof(variable) function.
2. The same applies to record variables and arrays.
3. Pointers and Objects require 4/8 bytes.
Every object (that is, class instances) is always allocated on the heap.
Value structures (simple numerical types, records containing only those types) can be allocated on the heap.
Dynamic arrays and strings content are always allocated on the heap. Only the reference pointer can be allocated on the stack. If you write:
function MyFunc;
var s: string;
...
Here, 4/8 bytes are allocated on the stack, but the string content (the text characters) will always be allocated on the heap.
So using New()/Dispose() is of poor benefit. If it contains no reference-counted types, you may use GetMem()/FreeMem() instead, since there is no internal pointer to set to zero.
The main drawback of New() or Dispose() is that if an exception occur, you need to use a try...finally block:
var
pCustRec : ^TCustomer;
begin
New(pCustRec);
try
pCustRec^.Name := 'Her indoors';
pCustRec^.Age := 55;
finally
Dispose(pCustRec);
end;
end;
Whereas allocating on the stack let the compiler do it for you, in an hidden manner:
var
CustRec : TCustomer;
begin // here a try... is generated
CustRec.Name := 'Her indoors';
CustRec.Age := 55;
end; // here a finally + CustRec cleaning is generated
That's why I almost never use New()/Dispose(), but allocate on stack, or even better within a class.
2
The usual case for heap allocation is when the object must outlive the function that created it:
It is being returned as a function result or via a var/out parameter, either directly or by returning some container.
It's being stored in some object, struct or collection that is passed in or otherwise accessible inside the procedure (this includes being signaled/queued off to another thread).
In cases of limited stack space you might prefer allocation from the heap.
Ref.
I'm trying to modify the VirtualTreeView to see data in the tree nodes in the design mode.
The allocating node memory is in the private static method so I can't do anything about it. I'm trying to reallocate the memory to match the new size then.
For the test purposes I'm trying to reallocate the same amount of memory:
ReallocMemory(Node, sizeof(Node^))
But the IDE hangs up in the random iteration throwing a lot of AV. Since my knowledge of memory allocation is pretty lacking I think I'm forgetting something. Could you point me please?
ReallocMemory is a function. It returns the new pointer value; it does not modify its argument. You want to call ReallocMem instead, or else use the result of the function:
ReallocMem(Node, SizeOf(Node^));
or
Node := ReallocMemory(Node, SizeOf(Node^));
When either of those functions cannot resize the block of memory in-place, it allocates new memory, copies the old contents into the new buffer, and then frees the original buffer. If you ignore the ReallocMemory result, then you have discarded the new pointer and retained the old, stale pointer in the Node variable. Continued use of a stale pointer would explain access violations and other unpredictable behavior.
There are two versions of those functions for C++ compatibility. C++ doesn't have Delphi's "compiler magic," which is what allows the compiler to have a single ReallocMem function that accepts and modifies any pointer type.
The ReallocMemory function looks like the C++ realloc function, but they don't behave quite the same way, which is why it's safe to directly overwrite the input variable with the function's return value. When reallocation fails, the function throws an exception, just like ReallocMem, where as realloc just returns a null pointer.
I have a piece of Delphi code
var
a: array of array of array of integer;
begin
try
SetLength(a, 100000, 100000, 10000); // out of memory here
doStuffs(a);
except
a = nil; // try to free the memory
end;
end;
The above code tries to allocate lots of memory and out-of-memory will be caught. The a=nil will be executed, but the memory isn't freed.
Is there a way to free the memory in the case of out-of-memory exception?
I tried SetLength(a, 0, 0, 0) and Finalize(a), and both won't work either.
In general, it's not possible to recover from an out of memory error. At that point the heap is most likely corrupted. The appropriate response is to terminate the process.
In this specific case, the allocation is performed by DynArraySetLength in the System unit. This performs repeated allocations. Only as the last act of DynArraySetLength is the return value, a in your code above, actually assigned. And if errors occur in DynArraySetLength then the runtime makes no effort to tidy up. Which means that in case of failure, any memory allocated is leaked and cannot be recovered. You have no way to refer to it in order to free it.
You may think that DynArraySetLength should do more to tidy up. However, it's approach is justifiable. Since out of memory conditions invariably result in corrupt heap, attempts to tidy up would just prolong the agony. Once the heap is dead, there's no point in trying to deallocate memory.