Applies To:
  • CitectSCADA 1.xx, 2.xx, 3.xx, 4.xx, 5.xx

This article discusses everything you wanted to know about memory leaks but were too afraid to ask.  

What is a memory Leak?

A memory leak is when a block of memory is allocated and never freed. If the memory allocation is repetitive, then over a long period of time the entire memory will be consumed. As you consume all the physical memory, windows will start to use virtual memory. You can tell when this is happening as the hard disk will start accessing constantly for no reason at all. The computer may then slowly degrade until the performance is slower than waiting in a bank queue. The computer may then finally freeze solid.

When you shutdown Citect, Windows will free all memory including any memory leaks. So if you see a degrading of performance and you re-start Citect and the performance returns that is a good indication that a memory leak is occurring.


What causes a memory leak?

Memory leaks can be caused in several ways. The first way, heavens forbid, there could be a bug in Citect that caused a memory leak. The other way is there could be a bug in your cicode or project.

If the memory leak is caused by a bug in Citect, you will need Citect Support to resolve the problem. To help them find the cause of the leak please use the procedure below to find the memory leak.

If the memory leak is cause by a bug in your cicode, you can modify the cicode to solve the problem. Memory leaks can occur in cicode if you call a cicode function that allocates a handle and you don't free that handle, you will have a memory leak*. For example this type of cicode will cause a memory leak.

hFmt = FmtOpen("Myformat", "{TAG}{NAME}{DESC}", 1);

A more common bug would be if you allocated a handle when you display a page. For example on the page entry cicode or attached to an animation. Each time the page is displayed or animation is updated you will get a memory leak.

* It is a common practice to allocate a handle at start-up and never free it, when that handle is used in a global context. This solution is used to simplify the cicode and increase runtime performance. Is not considered a problem as the memory will be freed on shutdown and the allocation is not repetitive, so it does not eat memory.


Finding memory leaks

The first thing when looking for a memory leak is to verify that you have actually got one. There is no point going off on a "Wild Goose Chase", looking for something that is not there.


Verify you have a leak

The Windows NT Task Manager shows a list of processes, their CPU and Memory Usage. However the Task manager is not very useful to check if you have a memory leak. The Memory Usage showed by Task Manger uses the memory working set and that is not a true indication of the total memory used by the process. You must use the Windows NT Performance Monitor to verify that you have a memory leak. This can be found under the System Tools in Windows NT 3.x 4.x or in the Control panel, Administrative Tools in Windows 2000.

Start the Performance monitor and press the + button to add a new performance counter to the trend view. Select PROCESS from the 'Performance object' list box and CITECT32 from the 'Select instance from list' list box. Then select PRIVATE BYTES, from the 'Select counters from list', press the Add button and then Close.

The performance monitor will start trending the 'Private Bytes' of Citect. If 'Private bytes' is constantly increasing then you have a memory leak. The Performance Monitor does not have the fancy trending features of Citect, and when it reaches the end of the trend it will wrap around overwriting the old data. So you must either write down the value or slow down the update of the trend. Citect's consumption of memory is very dynamic and will rise and fall as you change pages and various background processes execute. So you must check that private bytes is rising over several hours or even better days.

TIP: Its considered excellent QA procedures if you add this test as part of your commissioning process to verify you don't have any memory leaks after project or version upgrade.


Narrow the Leak Search

Note: Please see KB Q3588 for updated information on setting debugging parameters (these are set in the registry not the INI file now). 

Now that you have verified that Citect does have a memory leak you need to find the cause of the memory leak. Citect has extensive memory debugging built into the kernel to allow you to track down memory leaks. To turn on memory debugging set the CITECT.INI parameter [DEBUG]Memory=1.

For more information on the memory debugging see KB article Q3086 [debug]Memory=1.

Start-up Citect, display the kernel and then type 'PAGE MEMORY'. Press SHIFT down cursor until you reach the end of the debug heap. If you have a memory leak then the heap will be growing with each memory leak. A good indication of a leak is exactly the same size memory allocation occurring again and again with the same CallStackTrace. Be careful, as Citect will also allocate a lot of memory like this under normal conditions. So you have to sort out the wheat from the chaff as it were.

Scroll the suspected memory leak to the top of the window and press the verbose mode 'v' and write down the CallStackTrace numbers. Send these into Citect support along with the Citect Version/Service Pack. Also by looking at the contents of the memory in verbose mode you may recognize what the memory belongs to. For example if you see the text "{TAG}{NAME}{DESC}" and you know you have a cicode format which is exactly the same, you could suspect you have a cicode bug.

WARNING: You must turn [DEBUG]Memory off once you have finished debugging as this can cause performance degrading of you system.


Still cannot find the leak!

If you cannot find the leak using this method then what do you do apart from tearing your hair out. Not all memory allocated by Citect will show up in the debug heap, so you may not be able to find the memory leak using the above procedure. You will then have to do a search for the Citect operation that is causing the leak. This is standard fault finding procedure, where you run a set of simple tests that show the existence of the problem, run other tests which don't show the probem and find out what is different between the tests.

You can do this by running the Citect Example project to see if that also causes the memory leak. If the example project does not leak and your project does, ask yourself what is my project doing that the example project does not do. Could be PLC driver, complex cicode, database access, fancy Active X control or juicy graphics.

Try building a very simple project and keep making it more complex until you see the problem. Start with one graphic page displaying one tag from your PLC driver. Then add more and more features until you see the problem or you have added all the features of your project.

Once you know what feature of Citect is causing the memory leak then create the absolutely smallest Citect project that demonstrated the leak and sent it off to Citect Support. With this demo project, Citect support has advanced debugging tools that can quickly trace down the cause of the memory leak. The smaller the project the quicker the problem can be traced.