Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

EOutOfResources

64 views
Skip to first unread message

Wendell H. Morris

unread,
Jan 16, 1998, 3:00:00 AM1/16/98
to

Hi all,

I've got a Delphi 1 app (compiled with the Client Server version of
Delphi 1 that comes with the Delphi 2.0 C/S CD-ROM) that is having
EOutOfResources problems.

According to the compiler info, I've got a local heap of 8192, a stack
of 16,384 and data size of about 13,000. My program dynamically builds
several pages on a TNotebook at runtime (the pages are actually built as
part of the program's startup sequence... once they're there they don't
change for the entire session). Each page contains a somewhat large (40
to 80) number of TLabel and TEdit controls.

When I run the program I can usually get it to bomb with the
EOutOfResources exception when I click my way into the various pages of
the Notebook. Windows reports that it cannot create the window handle.

Originally I thought I was just running out of space in my 64K region,
so I moved a bunch of static data to the heap. This solved the problem
for a while, but as the program continued to grow, I started getting the
problem again. In my last episode with it I moved another 2.5K of
static data to the heap, but this time it didn't fix the problem.

OK, now for the really weird part. If I *reduce* the Stack size in my
program I don't get the EOutOfResources problem, at least for now.
Also, this error does NOT occur on Windows NT systems at all. It does
occur on *some* Win95 systems, but I haven't figured out a common
denominator for the systems it seems more likely to blow up on.

I need to know what could be causing this to occur. In Win95 my system
resources never drop below 50% free while the program is running. I
don't think I have a major resource leak (the problem occurs right away,
not just after the program's been running for a long time).

The online docs suggest that Object Pascal doesn't use local heap unless
you explicitly ask for it via the Windows API. Is it possible that
dynamically adding components to a TNotebook would somehow be scarfing
down part of my 64K region? InfoSpy doesn't seem to think I'm running
out of Stack space, and I've got all of the range / overflow checking
options turned on in the compiler.

Thanks for whatever light anyone can shed on this!

--
--- Wendell H. Morris: mailto:wmo...@mfm.com
---
--- MFM Communication Software, Inc.
--- 4460 Lake Forest Drive / Suite 218 / Cincinnati, OH 45242

Rodney E Geraghty

unread,
Jan 17, 1998, 3:00:00 AM1/17/98
to

Wendell,
This error (Error Creating Window) is normally the result of your app
running out of windows handles. Each windowed control on a form will use
up a windows handle once
it is displayed. Unfortunately when you then hide the form or change to a
different page of a TabbedNotebook the handle is not freed up
automatically. For example if you have a form with a tabbed notebook which
has 5 pages with 100 edit boxes on each page then as you look through each
page additional handles are used up for each control on that page. By the
time you get to the fifth page you will probably have maxed out the number
of handles available to the app (this is a fixed
number but I'm not sure what the limit is). One solution to minimize the
problem is to use non-windowed controls where possible. I.e. use a TLabel
and a TBevel instead of a TPanel.

Another thing you can do is to take a look at the code provided in TI3138
at Borland's web site ( http://www.borland.com/devsupport/delphi/ti_list/
). This shows how to handle the problem with Tabbed Notebooks and can
probably be adjusted to work for other situations.

Hope this helps!
--

Rodney E Geraghty
GERA-Tech
Ottawa, Canada
ger...@ibm.net

Wendell H. Morris <wmo...@mfm.com> wrote in article
<34BFE6B6...@mfm.com>...

Nick Hodges (TeamB)

unread,
Jan 17, 1998, 3:00:00 AM1/17/98
to

Wendell,

The problem doesn't lie where you've been looking -- you are running
out of Windows handles. Often, components like the TNotebook control
allow developers to create a whole lot of Windows (TEdits are
Windows...) requiring a whole lot of Windows handles. Windows NT has
no limitations on the number of windows handles it can assign, but
Win95 does. The reason you see it only on some Win95 machines is
because there are other apps running on these machines using a
variable number of window handles themselves, hence the intermittent
error.

The solution is varied. The most common way is to create and destroy
the controls on each TNotebook page as they are displayed, or at least
create and destroy the windows handles. There are third party
notebook controls out there that do this for you. The other is to
redesign your application to use a dialog interface rather than the
notebook interface. The former is probably more palatable. <g>

There may be other solutions that users have, so I hope someone will
chime in.....


Nick Hodges
TeamB

Peter Below

unread,
Jan 17, 1998, 3:00:00 AM1/17/98
to

Wendell,

if you are using a large number of TEdits you have a chance of running out
of local heap space. The local heap is not used by Delphi itself but it is
used by some Windows controls, e.g. TEdit. The space available for the
local heap is what is left of your 64K data segment after static data,
typed constants, Pchar constants, and the stack are subtracted. That is why
you can get more edits if you reduce the stack size. Of course this
increases the danger of running into a stack overflow condition.

If possible try to replace groups of edits with TstringGrids for input,
that drastically reduces the number of window handles required and also
decreases local heap usage.

Peter Below (TeamB) 10011...@compuserve.com)


Jochen Heyland

unread,
Jan 18, 1998, 3:00:00 AM1/18/98
to


Finally I understand that part of it. The fact that I could create more
Windows with fewer global variables was the last mystery...
My findings from experimentations running a 16 bit (D1) program under
3.1x, 95 and NT are:
- If only one program is running, you can create more windows under 3.1
than under 95. If many programs are running, 3.1 does worse than 95.
The maximum under 95 is less than 300 (@ 275) but is less related to
other programs than 3.1 (maximum @ 320).
- Under NT, the maximum is higher than under either 95 or 3.1x (@ 400).

The program I used simply created windows until it got an Error Creating
Window and was compiled with a 16K stack.

As stated above, decreasing the stack and removing global variables
helps some of the time. When the problem occurs because of the local
heap, the difference can be astounding. However, the local heap is not
always the limiting factor - changing the stack size in the above
program did not really affect the results.

Various orders in which the windows are created can also have an effect
- I have no idea why but have gained about 5 handles in some programs.

And the bad news:
The handle itself (Fhandle) is private, so you can never check to see if
it's been created (it will be as soon as you check it).

Now for the good news:
The handle property of a wincontrol (and descendants) creates the window
when necessary. You can destroy the handles without ever having to
worry about when to re-create them.

Mixed News:
You can't directly call DestroyHandle as that is declared as protected
for reasons I surely don't understand. However, using the technique in
TI 3138
( http://www.borland.com/devsupport/delphi/ti_list/TI3138.html ) you can
overcome that limitation and desctroy handles when switching tabs or
moving on to other forms. I kill _all_ the handles within a form when
it is deactivated (knowing that all visible controls will recreate their
handle when they are painted) and have gotten around the problems that
way.

Jochen

Wendell H. Morris

unread,
Jan 18, 1998, 3:00:00 AM1/18/98
to

First, thanks to all (Rodney, Nick, Peter, Jochen) who responded.
You've shed quite a bit of light on my problem.


Jochen Heyland wrote:
>
> Peter Below wrote:
> >
> > Wendell,
> >
> > if you are using a large number of TEdits you have a chance of running out
> > of local heap space. The local heap is not used by Delphi itself but it is
> > used by some Windows controls, e.g. TEdit. The space available for the
> > local heap is what is left of your 64K data segment after static data,
> > typed constants, Pchar constants, and the stack are subtracted. That is why
> > you can get more edits if you reduce the stack size. Of course this
> > increases the danger of running into a stack overflow condition.

Why don't the system resources show it if I am running low on space in
my 64K data segment (remember, I can crash with plenty of resources
still free)? Isn't that one of the things that's tracked? If not, how
can I find out how much space I have left in this 64K region (while the
app is running of course)? I guess what I'm really asking is whether
there's an easy way to tell if I'm running out of space in the 64K
region *or* if I'm running out of global window handles. For all I know
right now I'm getting hit by a combination of these two things (that
would explain some weird behavior I've been seeing).


> Now for the good news:
> The handle property of a wincontrol (and descendants) creates the window
> when necessary. You can destroy the handles without ever having to
> worry about when to re-create them.
>
> Mixed News:
> You can't directly call DestroyHandle as that is declared as protected
> for reasons I surely don't understand. However, using the technique in
> TI 3138
> ( http://www.borland.com/devsupport/delphi/ti_list/TI3138.html ) you can

> overcome that limitation and destroy handles when switching tabs or


> moving on to other forms. I kill _all_ the handles within a form when
> it is deactivated (knowing that all visible controls will recreate their
> handle when they are painted) and have gotten around the problems that
> way.

Thanks for the info! I've implemented a variation of what's in TI3138
and I think I've "solved" my problem for now (until my static data needs
to grow again). I do, however, have a question for you. According to
the sample code in the TI, they perform the DestroyHandle in the
TabbedNotebook1Change procedure. If I understand the process correctly,
won't that short circuit the fix since at the time they perform the
DestroyHandle the page is still displaying? I more or less confirmed
this suspicion by monitoring the system resources, but I'm not
positive. Of course, I'm using a TTabSet and a TNoteBook, so maybe the
behavior is different enough that the example code doesn't exactly
apply.

I moved the code around so that my Notebook displays the next page and
*then* I do a DestroyHandle on the previous page. That seems to do the
trick, but of course I'm wondering if I've done a bozo-no-no since
Borland's sample code seems to contradict this. I realize this method
means there will be times when two pages worth of handles are allocated,
but that's still better than having all of them allocated at the same
time like it was before.

Finally, I've noticed an annoying screen repaint (the entire desktop)
when I execute the LockWindowUpdate(0) line. Is there some way around
this? On a machine with slow video I imagine it's pretty horrible. Do
I really need to lock the page, especially since I'm now calling
DestroyHandle *after* that page is no longer visible?

Peter Below

unread,
Jan 19, 1998, 3:00:00 AM1/19/98
to

In article <34C27B85...@mfm.com>, Wendell H. Morris wrote:
> Why don't the system resources show it if I am running low on space in
> my 64K data segment (remember, I can crash with plenty of resources
> still free)?
>
Because the local heap is not a system resource, it is a resource of *your*
program and will only be used by controls you use inside your program. The
local heap will grow from the originally specified size up to the maximium
your 64K data segment can take. There are a number of functions in the
Win16 toolhelp unit that allow you to find out stuff about the local heap
(see LocalInfo, LocalFirst, LocalNext), there is a LocalCompact function
that can sometimes be used to reduce local heap fragmentation. There is no
way to find out how many windows you can still create, you have to try and
be prepared for failure.


Peter Below (TeamB) 10011...@compuserve.com)


0 new messages