User Tools

Site Tools


xff_-_memory_management
no way to compare when less than two revisions

Differences

This shows you the differences between two versions of the page.


xff_-_memory_management [2010/06/10 13:34] (current) – created jochen
Line 1: Line 1:
 +====== xff - memory management ======
  
 +===== Motivation =====
 +Matlab's only way of passing arguments into a called function is "by-value", which means that if the called function alters a variable (which can be highly complex, such as a nested struct!), the calling function needs to accept any such altered variables as returned values and re-assign them to their original variables. Here is an example:
 +
 +<code matlab matlab_pass_by_value.m>% the function called is fictitious, and would replace
 +% bad coordinate values in variables X, Y, and Z with
 +% NaNs in all three of them
 +[X, Y, Z] = nanbadcoords(X, Y, Z);</code>
 +
 +While this is relatively convenient (and Matlab's internal calling syntax detects that variables are to be overwritten, so unless an error occurs, there is little memory overhead), this is highly unusual if objects are used. Most object-oriented languages support a "call-by-reference" syntax, where the calling function only receives a reference or pointer to the actual object and any changes are thus automatically propagated to the calling function (and any function up the stack!).
 +
 +===== Implementation =====
 +In xff (and also the other NeuroElf classes, for that matter), storage is not allocated in the struct variable that constitutes the class object (which is true for most other non-NeuroElf class objects!). The only field in the struct variable of any xff object is the ''.L'' field which contains a unique lookup identifier that allows xff and its internal methods to locate the actual storage of the object:
 +
 +<code matlab>% creating an object
 +vmr = xff('new:vmr');
 +
 +% displaying the struct contents:
 +struct(vmr)</code>
 +
 +This would produce something like the following sample output:
 +
 +<file>
 +ans =
 +
 +    L: 0.6692
 +</file>
 +
 +The actual storage is kept in a global variable, ''xffcont'', which I recommend against altering manually:
 +
 +<code matlab>% intialize xff
 +xff;
 +
 +% display list of global variables
 +whos global</code>
 +
 +would produce (if no other global variables are present):
 +
 +<file>  Name          Size              Bytes  Class     Attributes
 +
 +  xffclup       1x1                    double    global    
 +  xffconf       1x1               29219  struct    global    
 +  xffcont       1x1             2700694  struct    global    
 +  xfflast       1x2                  16  double    global    
 +  xinimeth      1x1                5342  struct    global</file>
 +
 +These variables have the following content/meaning:
 +  * ''xffclup'' - content lookup list (contains one double number per loaded object, one of which is the ROOT object)
 +  * ''xffconf'' - xff configuration (global instead of persistent as it is used by some methods also)
 +  * ''xffcont'' - the actual storage of objects as a vector of structs, each having the fields
 +    * C - actual content (what is displayed when an object variable is used without a semicolon)
 +    * F - filename (empty if not loaded from disk and not saved yet, "''<ROOT>''" for the ROOT object)
 +    * H - sub-struct of handles to other objects (e.g. transimg objects for data slicing, etc.)
 +    * L - lookup value (for convenience stored also in the struct)
 +    * S - file format specification (extension(s), fields, etc.)
 +    * U - unwind stack information (used for the internal automatic garbage collection of xff)
 +  * xfflast - 1x2 double value, for which object was the fieldnames/methods function called last and second-to-last
 +  * xinimeth - method name storage of xini class; as xff uses xini for some settings, this class is also initialized
 +
 +===== Consequences =====
 +**As the storage is //NOT// directly associated with any given object variable, using Matlab's clear function on any such variable will not lead to the allocated memory being freed by Matlab!** Instead the ''.ClearObject'' call must be issued to free up memory:
 +
 +<code matlab xff_clearobject_sample.m>% create a new VMR
 +vmr = xff('new:vmr');
 +
 +% set random content
 +vmr.VMRData = uint8(100 + round(10 * randn(size(vmr.VMRData))));
 +
 +% save as (without argument requests for filename)
 +vmr.SaveAs;
 +
 +% clear object!!
 +vmr.ClearObject;</code>
 +
 +Without this last line, the associated memory would remain allocated even if this is used in a sub-function (which removes the vmr object from memory, but that only contains a struct with the ''.L'' field!).
 +
 +===== Garbage collection =====
 +To ensure that user-written functions do not clutter up the global ''xffcont'' variable with objects that are no longer in use, a garbage collection has been implemented into xff. This works as follows:
 +
 +  * for any object, the stack is recorded during object creation (which function created the object)
 +  * whenever any xff method is called, the stack of all remaining objects is checked, and if the current stack doesn't match, those objects are removed
 +  * to protect objects from being affected, the ''bless'' function must be called
 +
 +===== bless =====
 +Here is an example of a user-written function that creates an object which is suitable for passing outside of the function and not being affected by this garbage collection (it also creates another object which would be removed by garbage collection if the ''.ClearObject'' method would not be called):
 +
 +<code matlab spheresvmr_sample.m>function vmr = spheresvmr_sample
 +% spheresvmr_sample  - create a VMR with 10 small spheres
 +%
 +% FORMAT:       vmr = spheresvmr_sample;
 +%
 +% No input fields.
 +%
 +% Output fields:
 +%
 +%       vmr         VMR object with 10 spheres
 +
 +% create VMR object (output)
 +vmr = xff('new:vmr');
 +
 +% create VOI object as a helper
 +voi = xff('new:voi');
 +
 +% create 10 spheres in VOI
 +for c = 1:10
 +    voi.AddSphericalVOI(min(120, max(-120, round(40 * randn(1, 3)))), 7);
 +end
 +
 +% set those coordinates to 200 in VMR
 +for c = 1:10
 +    vmr.VMRData(bvcoordconv(voi.VOI(c).Voxels, 'tal2bvc', vmr.BoundingBox)) = 200;
 +end
 +
 +% make sure VMR is not affected by garbage collection
 +bless(vmr, 1);
 +
 +% destroy voi (would be removed by garbage collection some time later otherwise)
 +voi.ClearObject;
 +
 +% end of function</code>
xff_-_memory_management.txt · Last modified: 2010/06/10 13:34 by jochen