Axis2/C is becoming the most featured and stable and enterprise grade Web Services engine for C. Written in C, memory handling in Axis2/C is very crucial. This article written by Manjula Peiris discusses a few important tips related to memory management in Axis2/C. The article is recommended reading for Web service implementors, module writers and consumers of Web services in Axis2/C.
|
Date: Tue, 25th Mar, 2008
Level:
Intermediate
Reads: 3680 Comments: 0 |
Login or register to post comments |
|
|
|
Manjula Peiris Software Engineer WSO2 Inc. |
| |
|
Table of Contents
- Introduction to Axis2/C Memory Management Model
- Axis2/C with Apache2
- A Few Important Memory Management Tips
- Summary
- References
Introduction to Axis2/C Memory Management Model
Apache Axis2/C consists of a quite simple memory management model. If you are using Axis2/C as a standalone engine, then it uses malloc and free functions offered in the traditional C programming environment to allocate and deallocate memory. This changes as Axis2/C is used in other environments. Axis2/C ' s pluggable memory architecture allows environment specific memory management techniques to be plugged into Axis2/C. For example, if Axis2/C is used as an Apache module, memory management will be performed completely via apr memory pools. Therefore, as such, end users are able to benefit from advantages offered in these environment specific and better-tuned memory management mechanisms. Axis2/C does this using a concept called environment (axutil_env_t ) and allocator (axutil_allocator), where you can assign your environment specific memory allocator function and deallocator function. The following code segment describes how this is done.
axutil_allocator_t *allocator = (axutil_allocator_t *)<enviornment_specific_memory_alloc_fun>
allocator->malloc_fn = <function_pointer_to_enviornment_memory_alloc_fun>
allocator->free_fn = <function_pointer_to_enviornment_memory_free_fun>
allocator->realloc_fn = <function_pointer_to_enviornment_memory_realloca_fun>
In addition to the allocator, the Axis2 environment encapsulate a few other important environment properties. They are,
- axutil_error - to handle errors
- axutil_log - to handle logging
- axutil_thread – to handle threading
Axis2/C allows creation of environments, some that include certain existing properties and others, entirely new. You can create an environment with an existing axutil_error or a log. Following functions, as their names suggest does these relevant tasks for you.
- axutil_env_create - Create the environment with new error, log. The thread pool is not created
- axutil_env_create_all - Create the environment with new error, log and thread_pool
- axutil_env_create_with_error_log – Create the environment with existing error and log
- axutil_env_create_with_error_log_thread_pool – Create the environment with existing error, log and thread pool .
The procedure axutil_env_create_all is used to create the environment at system start up. Inside, new threads use axutil_env_create_with_error_log_thread_pool to create a thread-specific environment. But when creating a new thread environment, the best practice, is to use the following two functions defined in the axutil_thread_pool.h to initialize the threaded environment at the start, and then, to release it in the end.
axutil_init_thread_env – wraps function #4 for creation of the environment.
axutil_free_thread_env – frees only the environment, and retains properties for other threads.
Axis2/C with Apache2
To use Axis2/C in a production environment, the best approach is to use it with the Apache2 Web server. This way efficient handling of concurrent requests whilst gaining highest performance can be achieved. Since Axis2/C comes with a HTTPD module, this can be done very easily. Please read this manual for more information on configuring Axis2/C with Apache2. When used with Apche2, there are certain factors that needs to be understood in relation to memory. When you deal with Apache the scopes of resources are different. To gain high performance and prevent memory leaks, Apache uses apr_pool concept. The following three pools are very important when using Axis2/C with Apache2.
Request pool
- Apache creates a pool for each request. All resources with the same life time as the request should be created in this pool. This is called the local_pool inside Axis2/C.
Process global pool
- In Apache, a single process may handle more than one request. So, for resources with a life time beyond that of the request, should be created in this pool. Please remember other processes do not have access to this pool.
System global pool
-This is called shared memory. Where all the processes have access to it. Resources with a scope, beyond process lifetime, need to be created here. You can specify whether to use System global pool or not. Adding the global pool size directive in the httpd.conf will do it.
For an example, the following directive will set a 10MB shared memory pool. If this is not added, or set to -1, then the shared memory pools will not be used.
Axis2GlobalPoolSize 10
axutil_allocator.h defines two useful functions to switch between global and local pool. The default assumption is that everything is created in the local pool (request pool) . Therefore, in order to create some resource which has a lifetime beyond a single request a pool switch between local to global should be done. Calling following function will do it.
void axutil_allocator_switch_to_global_pool(axutil_allocator_t *);
So if you have enabled system shared memory as explained above , all the calls to AXIS2_MALLOC now creates resources in the system global pool. And you can access the resources created in the global pool. If shared memory is not enabled then the resources will be created in process global pool. It is a must to switch to local pool when ever you do not need the resources in the global pool. Not doing this may cause memory leaks , because the resources which need to be freed after a particular request now not freed at that point. Calling following function will switch the pool to local pool.
void axutil_allocator_switch_to_local_pool(axutil_allocator_t *);
A Few Important Memory Management Tips
Deep Copies and Shallow Copies
A deep copy is a new object of an existing object in memory. Here the new object will be created in memory and a reference to new object will be returned when created. Deep copying is suitable when the object size is small and creating the new one is not expensive. These new creation should be tracked and freed when ever necessary.
A shallow copy is a reference to an existing object. Shallow copies are more efficient and improve system performance comparing to deep copies. But managing them is difficult. Because one object may be referred from many others. In those cases freeing the actual object at the correct moment is very important. Incorrect handling of those situation may cause freeing an already freed object or memory leaks. A simple technique to prevent those situations is to use a ref count. This technique simply keeps the number of references to the real object as an integer value. Following are the steps to follow when using this technique.
- Set the reference count to one when the object is created.
- When another object keeps a reference of this newly created object as a member of it then increment the reference count.
- The freeing of this object will happen only if the following condition is satisfied.
if((--ref_count) > 0)
{
return;
}
else
{
free;
}
This technique will be very useful for module authors and service authors when memory management is complex and difficult.
A Few Important Tips when Dealing with Axiom
Axis2/C uses the Axiom object model to represent XML infoset. Any valid xml document or a SOAP message can be accessed through the Axiom object model. The most important point to understand when you are adding any text or elements to the Axiom object model, is that it takes the ownership of that object. So in the following cases, you do not need to explicitly free the memory unless you duplicate it. For example, in the following code segment the namespace created will be freed when freeing the corresponding axiom_tree.
axiom_namespace_t *ns = axiom_namespace_create(env, uri, prefix)
axiom_element_t *new_element = axiom_element_create(env, parent_node, localname, ns, container_node);
Therefore, explicit freeing of namespace will cause a double free. In the following code sample the caller does not need to free the text string returned.
axis2_char_t *text_string = axiom_element_get_text(om_element, env , om_node)
/* Do some thing with text_string*/
At the end you do not need to free the string pointed by text_string since it does get done when string's axiom_tree is destroyed.
Important Facts Dealing with Hash Tables and Array Lists
Axis2/C supports the use of hash tables and array_list using the functions defined in axutil_hash.h and axutil_array_list.h in util package.
When releasing memory belonging to these structures, we need to understand what exactly theie corresponding free methods do. Those methods frees only the structures but not the content inside.For example, axutil_hash_free(hash, env->allocator) will frees only the hash not the content inside it. Same happens for the method axutil_array_list_free. If you want the content also to be freed then you need to free them one by one using those corresponding elements free method.
When adding elements to a hash table or an array_list, those added elements should exist in heap memory. If they belong to a particular stack frame then they will disappear when that stack frame does. See the following code segment:
void my_method (axutil_env_t *env)
{
axis2_char_t *string = “test”;
axutil_array_list_t *list = axutil_array_list_create(env);
axutil_array_list_add(list, env, string); - wrong
axutil_array_list_add(list, env, axutil_strdup(string)); - correct
}
As illustrated in the code sample above, storing resources to hashes and array_lists, that lies only in the method scope will cause problems later on when you try to access them.
Summary
Axis2/C has a pluggable memory management model. The axutil_allocator and axutil_env are the key structures when it comes to memory handling in Axis2/C. Axis2/C has the advantage of apr memory pools when used with Apache2, but attention must be given to the scope of the resources. Correct decisions must be made, in order to choose between deep copying an shallow copying of objects. Special care need to be taken when working with Axiom and data structures like hash tables and array_lists.
References
- ws.apache.org/axis2/c/docs/axis2c_manual.html
- apr.apache.org/docs/apr/0.9/group__apr__pools.html
- Memory Management with Apache Axis2/C
Author
Manjula Peiris is a Software Engineer at WSO2. manjula at wso2 dot com