[DUG] Embarcadero article
Jolyon Smith
jsmith at deltics.co.nz
Wed Jun 17 13:58:51 NZST 2009
If you want garbage collection use Prism and run your apps in a managed
environment where garbage collection makes as much sense as it ever will on
current hardware.
In the meantime you can introduce garbage collection into your own code
quite easily by following a few simple patterns, with the added benefit that
your garbage will be collected deterministically.
Example:
In one project I am involved in, we are replacing ALL our database access
code with a new abstraction framework, part of which has involved
introducing a factory for all SQL queries and commands, yielding interfaces
to those objects:
Old code:
Var
Qry: TQuery;
Begin
Qry := TQuery.Create(TheTDatabase);
Try
Qry.SQL.Text := 'some SQL';
// Do work with qry
Finally
Qry.Free;
End;
End;
New code:
Var
Qry: IQuery;
Begin
Qry := Database.Query('some SQL');
// Do work with qry
End;
Not only does this remove a lot of boilerplate try/finally from our data
access code, but that Database.Query() factory method represents some
additional, not immediately obvious benefits. Namely that once all
references to any query object have been released, the object is not
immediately Free'd, but instead lives on in a pool.
(this is possible because we implement our own IUnknown for these objects,
rather than using the simple ref counted lifetime management implemented by
TInterfacedObject)
The pool is flushed periodically, but if some code later requests a query
for 'some SQL' from the pool, and if the required SQL object still resides
in the pool, it can be retrieved without having to create a new TQuery,
assigning the SQL and re-preparing that statement on the server etc.
The pool also takes care of re-use issues.
That is, if 'some SQL' exists in the pool but is already in use (we track
that via reference count) then the factory will yield a new, non-pooled
query object rather than returning a reference to the already in-use query
(since nested/recursive uses of the same query objects will almost certainly
cause problems).
A previous caching mechanism that was used in the code did not make such
allowances and occasionally caused problems when some code called for a
cached query but was unaware that somewhere up the call stack some other
code was already working with that same cached query. Interfaces provide
the automatic reference tracking that allows this mechanism to be reliable
in the new implementation - the previous caching implementation could have
implemented something similar but would have been vulnerable to people
forgetting to call "Free" when finished working with a cached query.
So, we got garbage collection (not universal, but for this VERY common
aspect of our code) AND performance improvements AND a less error prone
infrastructure.
And all without having to sit around waiting for CodeGear to add stuff (all
this in code that will compile and run beautifully in Delphi 3 ... if it had
been necessary).
:)
--
"Smile", they said. "it could be worse!"
So I did. And it was
More information about the Delphi
mailing list