4

On occasion when GlobalAddAtom is called I get a NULL Atom back. Formatting the error from GetLastError shows "Not enough memory resources are available to process this command", but using Jordi Corbilla's Atom Table Monitor I can see that only about 2000 Global Atoms are used (1800 of which are RWM Atoms). What other system resources does GlobalAddAtom require?

Background: We have found in some cases that Delphi TBitBtn would not draw (esp. on computer systems where two very large and complex Delphi application were repeatedly opened and closed). I found that FindControl in vcl.Controls.pas would think it successfully found the Control Atom like this: GlobalFindAtom(PChar(ControlAtomString)) = ControlAtom, but the ControlAtom is actually NULL, so the test always incorrectly passes.

My first idea was that the Atom associated with ControlAtomString was not properly disposed (earlier versions of Delphi did indeed have Global Atom leaks), and that the same string from a prior run was reused. Since its composed with an HInstance and ThreadID, the chances are slim, but not impossible. This was not the case. I could use Atom Table Monitor to verify the name was unused, plus the frequency of errors were too high to be name collisions

With this information I set off to see if I could trap any Atom errors and found the one listed in my more succinct question above.

A Minimum Reproducable Expample is not easy to create. The applications related to problem are very large and often need to run for several weeks, or opened and closed with a utility thousands of times before the problem rears its ugly head.

Once a system gets into a mode where this unknown system (global) resource is depleted the problem can be reproduced with relative frequency in any application with a TBitBtn. A simple application with a single TBitBtn that is is opened and closed a few times (often only 3 or 4 times) will frequently fail to show the button

Jasper Schellingerhout
  • 1,070
  • 1
  • 6
  • 24
  • Have you tried using madExcept to check your application runtime behaviour? madExcept is capable of detecting many leak types. The doc says: ...all kinds of memory allocations (both by the Delphi memory manager and by win32 allocation APIs), kernel handle leaks, GDI handle leaks, user handle leaks, shell handle leaks etc etc. Leaks are reported when your exe/dll is closed/unloaded. – fpiette Feb 19 '20 at 14:57
  • @fpiette most leaks are disposed when a process is unloaded. As far as resources that persist after a process is unloaded, what is the list of those esp. as it relates to Global Atoms? – Jasper Schellingerhout Feb 19 '20 at 15:17
  • If I understand correctly you already have a modified controls.pas. You can modify the check to additionally test for a null atom for FindControl to fallback to ObjectFromHwnd as a workaround in the meantime. – Sertac Akyuz Feb 19 '20 at 15:31
  • @SertacAkyuz I could fix this specific bug in `FindControl`, but this is not the cause of the unknown resource being depleted. Old applications in Delphi are still affected – Jasper Schellingerhout Feb 19 '20 at 15:36
  • Something is strange here. ControlAtom is initialized only at startup. You should observe symptoms right then, not after weeks of usage... That is assuming your buttons are in the executable... – Sertac Akyuz Feb 19 '20 at 15:50
  • @SertacAkyuz I added an extra paragraph. The system takes weeks to "break", but once "broken". The symptom is pervasive – Jasper Schellingerhout Feb 19 '20 at 16:19
  • 1
    I believe that the global atom and window message tables may be impacted by the desktop heap as well: is this a desktop app where other things on the desktop continue to work OK, or is this a service app that runs non-interactively? Also, what exact error number is being returned by the failure of allocating an atom? – Steve Friedl Feb 20 '20 at 05:33
  • @SteveFriedl I believe its System Error 8. ERROR_NOT_ENOUGH_MEMORY. Other applications are mostly unaffected, Delphi applications with `TBitBtn` consistently affected (even trivial ones as described). I am wondering if `SetProp` can cause an ATOM's resource to be held if `RemoveProp`was not called (even if its "removed" from the Global Atom List). But this is me grabbing at straws – Jasper Schellingerhout Feb 20 '20 at 13:00
  • #8 can also mean out of desktop heap, but that would impact other apps in the same session space because desktop heap exhaustion is something you notice. 2000 atoms is not really a concern. How are the global window messages doing? – Steve Friedl Feb 20 '20 at 14:53
  • I've had to deal with this issue for a long time with a customer's line of business application, and I built some tools that helped me with troubleshooting. I packaged up the one most on point and have it available on BitBucket - perhaps this will be helpful. https://bitbucket.org/SJFriedl/query-atom-table/src/master/ – Steve Friedl Feb 20 '20 at 17:15
  • @SteveFriedl Thanks, your tool reports similar to Jordi's tool (on this affected machine ~700 global, ~1700 RWM). The guy with the affected system had to restart because his Windows Explorer shell stopped live updating folder content, plus the issue affected other Delphi Apps such as InstallAware. I'll leave this item open until I find another affected system or maybe can answer this myself – Jasper Schellingerhout Feb 20 '20 at 19:35
  • @JasperSchellingerhout - So not a matter of atoms/RWM, it's for sure desktop heap, and there are scares few resources here - it's maddening. These are allocated per session, so logging out and back in should "fix" it, right? One thing to try is Task Manager, details page, right-click on a column header and Select Columns for "user objects". I believe these are related to the resources in question, but this is still a longshot. – Steve Friedl Feb 20 '20 at 19:45

0 Answers0