All your atoms belong to us

Many developers for Windows used to fact that all resources that you allocated in your application will be released when your process is closed. And in fact, many developers read Windows API function description by diagonal ignoring most of it. Please read it carefully and I will explain why.

Few years ago, developers started to hit the same problem: application failed to start with some stupid unrelated error and in fact all application failed to start again with some strange error. Restart always fixes this problem, so we blamed Microsoft and move on. In some cases, you even cannot restart your PC due to the same strange errors. But we time it start to happen more and more often. And finally, one guy found source of the problem. It called atoms.

You can read about it here: https://docs.microsoft.com/en-us/windows/desktop/dataxchg/about-atom-tables. In short there is quite limited (by current date’s standards) table that contains integer and string atoms. Total size of the table is 65535 items. There are 0xC000 integers atoms and 0x4000 string items.

There is global table for whole system and local table per each process. Obviously, everything you added to local table will be freed after you process closed but global table is global. And if you used all global integer or string atoms then your system is doomed. Application will crash with strange reasons; new applications will fail to start and as I said in some cases you even cannot restart. And if you process used all local atoms it will usually crash but it is less problem because you can restart application and not whole system.

You may say: “I don’t use atoms so I’m safe”. And you will be wrong. A lot of Windows API functions uses atoms. For example, RegisterClass, RegisterClassEx uses local atom table. And here is some of function that uses global atoms: GlobalAddAtom, RegisterWindowMessage, RegisterClipboardFormat. So, if you are using one of these functions keep in mind that it is global. If your application forgot to remove it then it will stay there. If your application crashes or user kill it then it will also stay.

In most cases using of these functions are ok, because it is used with some string constant. Like RegisterWindowMessage("MY_AWESOME_MESSAGE") and even if your application crashes it will leak one atom. When user restarts your app, this string is already registered, and Windows will return existing atom. But if you are trying to generate unique string then you have problem in your hands. Imagine you generate GUID, convert it to string and use it as message string. Every time your application closed ungracefully there will be one atom leaked. So, you have a bit more that 16 000 such events before you got into problem. It sounds a lot but keep in mind that there are already a lot of atoms used by other applications and by Windows itself. For example, .Net Framework registers about 30-40 window messages. Some of them have versions. There is a bit of clipboard formats registered. But in any cases probably your customers will not encounter this problem unless it is used on some equipment that works for many months without restart like some medical equipment.

But your developers will have this problem. Most of the time developers will not close application gracefully. They usually stop application in debugger and this way global atom will always leak. Say you started application 30 times per hour (start it every 2 minutes) and for 8 hours it will 240 atoms leaked. 1200 per week.

In our case runtime for language we are using creating unique 2 atoms for each dll. It uses base address of dll and thread id as part of atom names. In our project there are about 260 dlls and each will leak 2 atoms. So, start and stop application in debugger leaks a lot of handles (not every dll loaded on application start). And as result, every 1 – 2 weeks we had to restart our PCs.

I hope it helps someone.