RAM memory concerns|OPC UA Implementation: Stacks, Tools, and Samples|Forum|OPC Foundation

Avatar
Search
Forum Scope


Match



Forum Options



Minimum search word length is 3 characters - maximum search word length is 84 characters
Lost password?
sp_Feed sp_PrintTopic sp_TopicIcon
RAM memory concerns
Avatar
Andy Rehn
Member
Members
Forum Posts: 3
Member Since:
03/03/2026
sp_UserOfflineSmall Offline
1
05/20/2026 - 23:35
sp_Permalink sp_Print

Hi,

We are developing an OPC UA server based on on the library 'OPCFoundation.NetStandard.Opc.Ua.Server'. The server exposes data of building automation controllers (up to 500 devices). We are now a bit worried that the address space will take up too much RAM, since each object is represented by a number of nodes that must be stored in memory.

What generally consumes the most memory in an OPC UA server? Is it the storage of the address space, or other factors such as subscriptions and monitored items?

Please guide us regarding memory consumption in an OPC UA server. Maybe we're worrying about nothing?

 

How we are currently working:

We model our object types in a ModelDesign.xml file and then compile it with ModelCompiler. Then we load the .uanodes file generated by the compiler in our node manager class. To add an object (set of nodes) to the address space of the server we create an object instance of one of the classes that are generated by the compiler and then call CreateNode with that instance as inparameter (we also create references). As we understand the address space (all nodes) are cached in CustomNodeManager2::m_predefinedNodes.

Avatar
Randy Armstrong
Admin
Forum Posts: 1689
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
2
05/21/2026 - 16:02
sp_Permalink sp_Print

The generated C# classes are great for small servers or if a rapid prototype is needed, however, if your production application has high requirements you will likely want to invest a NodeManager that is designed for your data.

The understand the value of this approach you must see a UA information model as a window on your data rather than a database.

What this means is you do not need represent a device as 10+ nodes in memory. You instead build a NodeId structure that allows to response to Browse/Read/Write/Call on demand.

This means the only thing you actually need in memory is a structure that describes your device. All of the information associated with various Nodes used to represent your device are collected on demand by merging the static model with the device specific data..

To illustrate this concept a NodeManager for 100 million Nodes was implemented here:

https://github.com/OPCFoundati.....moryBuffer

Avatar
Andy Rehn
Member
Members
Forum Posts: 3
Member Since:
03/03/2026
sp_UserOfflineSmall Offline
3
09/21/2026 - 23:43
sp_Permalink sp_Print sp_EditHistory

Hi, Thanks for your answer! I have studied the MemoryBuffer-files as you suggested.

I have an idea to model static parts (parts that are the same across all controllers) of a controller in a ModelDesign.xml file to utlize the framework as much as possible. As I understand it you get a lot out of the box (such as browsing) and support by the partial generated classes where you can put your implementation code. The static parts are not too extensive and can be cached in PredefinedNodes or similar.

Then treat the dynamic parts (parts that differ from controller to controller) more like the MemoryBuffer with no or sparse caching and custom browsing.  The question is how I can best achieve this? Same or different nodemanager for the two parts? Which nodemanager to use/start off from? Represent dynamic parts with NodeState-derived classes (like MemoryTagState) or custom lightweight classes? Are there cases where it is a good idea to skip using NodeState-derived classes?

I'm getting a bit confused by all different examples, and I find it difficult to become any wiser by reading the documentation. I can't find a user-friendly documentation which can guide me in the correct direction. There are som many different examples starting off from different nodemanager classes or interfaces (CustomNodeManger2, SampleNodeManager, INodeManager, INodeManager2...). It is difficult to get a clear view of the differences between the different nodemanagers. Seems like a tedious task to implement a nodemanager interface from scratch. Dynamic data is sometimes represented by NodeState and somtimes by custom lightweight classes. And so on...

I would really appreciate some help!    

Avatar
Randy Armstrong
Admin
Forum Posts: 1689
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
4
09/30/2026 - 20:10
sp_Permalink sp_Print

The main documentation are the examples.

If you need to optimize memory/lookup you need a custom nodemanager and hand code most of the operations.

However, you can instantiate the auto-generated classes as part of processing request.

i.e. create a instance of a generated class, fill it its current values an pass it to other code that uses the standard API to read the values.

Avatar
Andy Rehn
Member
Members
Forum Posts: 3
Member Since:
03/03/2026
sp_UserOfflineSmall Offline
5
10/02/2026 - 02:35
sp_Permalink sp_Print sp_EditHistory

Hi, Thanks for your answer!

Another question after I have started coding the static parts where it is ok to cache nodes in PredefinedNodes:

I have modelled an object type with a number of properties and variables in a ModelDesign.xml file. Then I create an instance of that type at server startup. Some of the properties and values are dynamic and their values are read from a controller. In order to do that I have registered a read eventhandler on their OnReadValue (BaseVariableState::OnReadValue) event. The read operation to the controller, which is invoked in the eventhandler, is async, but I wait for it to return in the handler (blocking). The MemoryBuffer example rely on the OnReadValue event to handle reads...

Will this solution lead to bad performance? Is it better to override CustomNodeManager2's virtual read method which has a list of nodes to read as input. Here it will be necessary to "route a node to its corresponding read handler", but it would be possible to make several async read operations to the controller for multiple nodes at the same time and wait for all before returning. In this way there would be several async operations running in parallel.

Or is the only right way to create an instance on demand and fill in its current values and never cache even smaller static parts.

Avatar
Randy Armstrong
Admin
Forum Posts: 1689
Member Since:
05/30/2017
sp_UserOfflineSmall Offline
6
10/04/2026 - 18:07
sp_Permalink sp_Print

Creating a custom NodeManager gives you the freedom to optimize or not optimize as it makes sense for your application.

Whether any specific approach is better or worse depends on the details.

i.e. it is possible to design a custom NodeManager that ends up using more RAM than standard class based model if simultaneous access is needed from many clients. You will need to benchmark different design approaches to determine which best meets your requirements.

Forum Timezone: America/Phoenix
Most Users Ever Online: 1361
Currently Online:
Guest(s) 28
Currently Browsing this Page:
1 Guest(s)
Top Posters:
Forum Stats:
Groups: 2
Forums: 10
Topics: 1531
Posts: 5184