=================
Memory Management
=================

|HPSNOW| is a retained-mode visualization component, and system memory is allocated in order to store the contents of the scene graph and support the renderer. Since your application makes |HPSNOW| API calls to populate the scene graph, your application code is effectively responsible for the amount of memory that the application uses. This is similar to other non-|HPSNOW| data structures which are allocated by your application. While |HPSNOW| does monitor video memory usage, it does not monitor available system memory or make any attempts to limit system memory usage. It will attempt to allocate any system memory that is required as a result of your application's |HPSNOW| API calls. Note that file load operations also consist of |HPSNOW| API calls which populate the scene graph.

Your application should ideally contain its own memory management logic, which could include one or more of the following items:

* Tracking memory usage for all of its data structures and subcomponents, including|HPSNOW|  
* Providing end users with recommendations about the size or number of data files that can be loaded and interacted with simultaneously
* Indicating to the end user the amount of available system memory


.. _memory_manager:

|HPSNOW| Memory Manager
=======================

The dynamic allocation and releasing of memory in |HPSNOW| is controlled by an internal memory manager. The memory manager may allocate memory in numerous situations, such as when objects are inserted into the database, an update is performed, or files are loaded. As items are removed from the database, the memory manager takes care of the freeing of the memory associated with them. |HPSNOW| allocates memory using its own memory pool and attempts to reuse memory chunks after entities are deleted.

Tracking and management of |HPSNOW| memory usage should be handled in your application logic, and is facilitated by calling ``HPS::Database::ShowMemoryUsage`` which lets you query the amount of memory that |HPSNOW| currently has allocated, along with how much is currently being used. 


.. _relinquishing_memory:

Relinquishing Memory
====================

If you find that there is a significant gap between the amount of memory that |HPSNOW| has allocated and the amount in use, and you wish to reclaim some of that memory, you can consider asking the system to relinquish memory by calling ``HPS::Database::RelinquishMemory``. This forces unused memory to be released back to the system, essentially overriding the normal function of the |HPSNOW| memory manager. This function should only be used in very specific situations. See the Reference Manual entry for more detailed information. 


.. _out_of_memory_conditions:

Handling Out-Of-Memory Conditions
=================================

|HPSNOW| provides an optional mechanism which allows it to inform you about its memory usage, and help avoid a case where it attempts to utilize more system memory than is currently available. Such a condition is important to plan for, as system instability can result if unhandled.

The mechanism involves the use of an ``HPS::EmergencyHandler`` that you create. |HPSNOW| will call your custom handler's ``HPS::EmergencyHandler::Handle`` method if any emergency conditions are detected. Handle is called with a message and an error code. The values in ``HPS::Emergency::Code`` describe the the various types of conditions that can cause an emergency.

	**NOTE:** Emergency memory usage situations must be handled synchronously, and therefore the asynchronous event handler mechanism and its support for errors and warnings via ``HPS::ErrorEvent`` cannot be used. Additionally, calling any |HPSNOW| API function from your ``EmergencyHandler::Handle`` function (for any emergency code) may cause a deadlock.

Your emergency handler must derive from ``HPS::EmergencyHandler``. Here's an example of a custom handler:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_emergency_handler.cpp
		   :start-after: //! [MyEmergencyHandler]
		   :end-before: //! [MyEmergencyHandler]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_emergency_handler.cs
		   :start-after: //! [MyEmergencyHandler]
		   :end-before: //! [MyEmergencyHandler]
		   
To enable the emergency handler created above, you need to call:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_emergency_handler.cpp
		   :start-after: //! [set_emergency_handler]
		   :end-before: //! [set_emergency_handler]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_emergency_handler.cs
		   :start-after: //! [set_emergency_handler]
		   :end-before: //! [set_emergency_handler]
		   
The three emergencies you should handle are described below:


Soft Memory Limit
-----------------

The soft memory limit is an arbitrary value that you specify. When |HPSNOW| allocates more memory than the limit, it will call the ``HPS::EmergencyHandler``. However, the soft memory limit is just a warning - |HPSNOW| will continue to allocate memory. As the user, it is up to you to execute the logic (cancel the current operation, warn the user, close any open models), as to reduce memory usage. A soft memory limit is set with ``HPS::Database::SetSoftMemoryLimit``.

In the sample handler above, the code is responding to the ``HPS::Emergency::Code::SoftMemoryLimit`` code by aborting a file load, since continuing with a file load might eventually result in an out-of-memory condition as more memory is allocated. If a current file load was aborted, an application would likely be able to continue safely operating on any current |HPSNOW| scene graph. The handler cannot make any |HPSNOW| API calls directly or indirectly - the appropriate approach would be to post some sort of a message (or set some flag) which the separate file loading logic would check, and then abort its loading logic. Depending on your application memory management strategy, you may wish to:  

* abort any new file load
* report to your end user that there is a limited amount of memory remaining
* recommend to your end user that files or projects should be closed before opening new ones

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_emergency_handler.cpp
		   :start-after: //! [set_soft_memory_limit]
		   :end-before: //! [set_soft_memory_limit]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_emergency_handler.cs
		   :start-after: //! [set_soft_memory_limit]
		   :end-before: //! [set_soft_memory_limit]

Setting the memory limit value to zero will remove the soft memory limit.


Hard Memory Limit
-----------------

The ``HPS::Emergency::Code::HardMemoryLimit`` code occurs when |HPSNOW| attempts to allocate system memory and that allocation has FAILED. This is severe, and it is possible that system instability could occur. In this case, the sample custom handler elects to free a previously reserved emergency buffer. The sample code which reserved the emergency buffer is not shown, but it would consist of allocating a memory block with ``new``. Freeing a buffer and cancelling the current operation is usually the best method to regain system stability. However, returning to stability cannot be guaranteed. A reasonable amount of memory to reserve in the general case is 128 MB, although this will vary from system to system.


Fatal Errors
------------

If allowed to continue, |HPSNOW| will internally attempt to relinquish the unused portion of its allocated memory (do not try to call ``HPS::Database::RelinquishMemory`` yourself) before retrying the memory allocation. If the memory allocation after the relinquish fails, *it is a fatal error*.

If a fatal error occurs, the application CANNOT successfully return. The best you could do is have the application gracefully exit (and perhaps display a dialog box), which would require performing a ``longjmp`` to a point in the code previously saved by ``setjmp``.


Handlers for Specific Operations
--------------------------------

The above examples set an emergency handler for the general case. You can also set logic to handle a specific operation. For example, if you want to set a unique handler for file loading a particularly large file, you could use the following logic to do that:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_emergency_handler.cpp
		   :start-after: //! [load_file_example]
		   :end-before: //! [load_file_example]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_emergency_handler.cs
		   :start-after: //! [load_file_example]
		   :end-before: //! [load_file_example]
		   