Optimize app memory usage

Tune the Guardium® application framework to optimize app memory usage.

Apps that run on the Guardium Console are limited 200 MB of memory. When an application exceeds this threshold, logs are generated in the /var/log/guardium.error file. Eventually, the container that hosts the app shuts down and is restarted if the application continues to use even more memory beyond this threshold.

You can help prevent your app from exceeding the 100 MB threshold in three ways:

  • Avoid allocating large amounts of memory by chunking up (or staggering) the work into small memory footprints.
  • Change the memory model used by the application framework.
  • Call for garbage collection when finished with code that uses large amounts of memory

Changing the application framework memory model

By default, the application framework configures the Werkzeug WSGI web application server that Flask uses to run as a single process. Threads are used to handle each request. You can configure the application server to create a separate process to handle each new request. When the request is completed, the process is destroyed. All memory that is allocated by the Python interpreter to process this request is released.

To override this behavior, edit the run.py file and set threading=False and process=N where N is greater than 1. For example, a value of process=3 allocates approximately 25 MB per interpreter and so leaves some room for growth.

__author__ = 'IBM'

from app import app
from app.gpylib import gpylib

gpylib.create_log()
app.run(debug = True, host='0.0.0.0', 
threaded=False,
 process=3)

Include the source to the run.py in the template folder within your application ZIP archive file. The run.py that is created during the installation is then overwritten with your settings.

Calling for garbage collection

Python might not know when to free the memory. You can speed up garbage collection by placing the following code right after sections where large amounts of memory are no longer needed:

import gc
gc.collect()
Note: Python does not guarantee that any memory that your code uses gets returned to the OS. All that garbage collection guarantees is that the memory used by an object that is collected is free to be used by another object at some future time. Changing the application framework memory model option that is noted in the previous section is important for applications that run for a long time. Killing the process always guarantees the memory is freed for use by other components.

Tools

Some tools that can help you identify memory problems:

Memory Profiler
A Python module for monitoring memory consumption of a process. For more information, see Python Memory Profiler.
Linux utilities
The command line utility top can be used to monitor all Python processes running on the machine:
top -p $(pgrep -d',' python)

You can also use the following command to get the total MB used by all Python interpreters on your system:

ps -e -o pid,comm,rss | 
grep python | awk '/python/{print $3}' | 
awk '{sum+=$1} END
Resource Module
You can log the amount of memory your process uses by adding the following code to your module:
import resource
print 'Memory usage: %s (kb)' % resource.getrusage
(resource.RUSAGE_SELF).ru_maxrss