Archive for August 28th, 2005

Objects on the Stack: A Delphi Relic

Now here’s a dangerous and dubious technique for you to try at your own risk–
allocate objects on the stack instead of on the heap. Hey, C++ does it all the
time!

The advantage: object allocation is at least twice as fast on the stack.
Disadvantage: only applicable to objects which are local variables.

Example

First, an example and then the explanation.

uses
StackObjects;

procedure Test;
var
t : array [0..199] of TMyObject;
n : Integer;
begin
StackObjects.BeginStackAllocation(200*50, false);
for n := 0 to 199 do
t[n] := TMyObject.Create;

StackObjects.EndStackAllocation;
end;

Notice that t is a local variable–an array of objects. To get those objects
allocated on the stack along with the array itself all you need to do is call
BeginStackAllocation before they are created. BeginStackAllocation
reserves a portion of the stack for allocations (I’ll explain the boolean
parameter later). If you don’t reserve enough space an exception will be
raised. You might also have to use the $M compiler directive to make enough
space available. Then you just go ahead and create and use the objects as
you see fit. Finally, after you are through using them you call EndStackAllocation,
after which object allocations revert to the heap as usual.

Notice that there is no need to Free the objects on the stack. They automagically
vanish when they go out of scope. Reference-counted variables (e.g., dynamic
arrays) needs to be treated carefully and explicitly finalized before ending the
stack allocator. You also have to be careful that you don’t (explicitly or implicitly)
create any objects from a superior scope between calls of Begin- and EndStackAllocation
or they will vanish too and explode your app. The VCL user-interface is the
source of potential problems in this regard which the attached demo discusses
ways of getting round.

The stack space set aside by BeginStackAllocation is available wherever it is in
scope. This applies to procedures too. Memory allocated in an inner scope may
be safely used in the original scope. You could, in principle, make your whole
program into a procedure and put all allocations on the stack. I haven’t tried
that yet!

How it Works

Deep in the grids.pas unit the VCL itself uses this technique to allocate memory
on the stack. The trick is to shift the stack pointer to make room for your
extra variables. Such allocations disappear when the current procedure exits.
Grids uses two routines, StackAlloc and StackFree, to achieve some very fast
dynamic memory allocation.

I’ve adapted the method to work with other Delphi objects instead of just plain
vanilla memory and in the process made it a little safer. What the StackObjects
unit does is provide a plug-in Delphi memory manager that uses stack memory.
When BeginStackAllocation is called the new stack memory manager replaces the
standard memory manager and all subsequent memory allocations come from the
reserved space on the stack.

Now re-routing ALL memory allocation to the stack causes a number of problems.
It is amazing how hard it is to keep track of all the string variables that get
allocated behind the scenes and linger to blow up your app. For this reason all
dynamic string allocations are kept from the stack and re-routed to the standard
memory manager. In addition the stack memory manager can either handle all the
remaining allocation (including ordinary memory, and dynamic arrays) or just
the allocation of objects. Remember the boolean parameter in BeginStackAllocation.
If true is passed, only objects are created on the stack. Otherwise New and Dispose,
StrAlloc, StrDispose, GetMem, FreeMem, creation and destruction of dynamic arrays,
etc. all allocate on the stack.

It is essential to call EndStackAllocation before leaving the local scope. It reinstates
the default memory manager. If you don’t you’ll blow things to pieces. You could
use a try … finally block to ensure the memory manager is replaced in the event of
a problem but that might cause some stack-allocated entities to be freed by the
standard manager with more explosions!

The commented code in StackObjects.pas and the demo should explain the details.

Dangers

Make sure you match BeginStackAllocation and EndStackAllocation

Beware of implicit creation of objects from a superior scope

Don’t try and use with multiple threads.

Don’t try and use with other memory managers–at least not while stack allocation
is in progress.

This is an edgy technique, subverting Delphi to squeeze out some extra speed.
If I haven’t already made myself clear on this point … don’t blame me if,
in trying this code, you destroy your computer or start World War III.

August 28th, 2005

Sunday Week 22 Year A

Though you might not guess it looking at me I’ve never been on a surfboard. I’ve never been a surfer—if you don’t count channel surfing and my mastery of the remote—but I have watched them once or twice and found it stunning— audacious and beautiful and dangerous. The heart of the surfer’s art is an unusual balance—not just the physical balance of walking on water but another balance between bodily grace and crippling calamity. They ride the edge of a wave pushing their skill right to the brink of injury and death in search of the experience of really living. And when they find it they light up: they risk losing their life to find it.

We talk about ‘bearing our crosses’ in tones of resignation—fate has dealt me this hand and now I’ll offer it up and find some spiritual meaning in what I can’t avoid…
But Jesus must have been a surfer. When he says ‘renounce yourself and take up your cross’, when he says ‘lose your life and save it’, there’s no resignation in it—he’s talking about seeking out the edge where something is worth dying for, finding the place where death makes life worth living.
Matthew says Jesus was destined to go to Jerusalem to suffer but that makes it seem he had no choice. He did. Go home and die a safe man’s death or carry the cross of his good news into the Holy City riding the edge of his art, hoping for life abundant.
We know the wave broke, and broke him with it, but what a ride it was—audacious and beautiful and dangerous! And what a life came from his death!
Surfers, for all their dopey cool, are addicts and obsessives. Once they have balanced on the edge and tasted the wave they can’t get the thirst from their mouths. They pursue those waves: challenge them, push their luck to the breaking point and beyond.
Jeremiah is protesting and praising just that experience. ‘You have seduced me God and I have let myself be seduced. You have been too much for me but I cannot forget you. I cannot be silent, I cannot un-speak your name, or swallow your words—they throb like a fire in my heart and a burning in my bones.’

My advice to you (and to myself) is to go home and stick to channel-surfing. The less you risk the less you feel. The less you feel the less you risk. … Avoid Jesus at all costs. Because if you let him in, if you let him close, if you feel his touch—he will seduce you and you will let yourself be seduced. Better, my friends, not to know him, better not to get the taste for him and his crazy, wonderful life.

Of course it may already be too late.

August 28th, 2005


Calendar

August 2005
M T W T F S S
« Jul   Sep »
1234567
891011121314
15161718192021
22232425262728
293031  

Posts by Month

Posts by Category