.. _cs-memory-handling-label: C# Memory Handling ================== **This sections aims to clarify the importance of handling memory objects correctly and with best practice. This is important when you work with very large in-memory images, that Phase One SDK's provides.** As a C# developer you would normally rely on the :term:`Garbage Collector` to do memory handling for you. The objects you create with the ``new`` operator, will automatically be disposed, i.e. freed, when they are no longer used. In special cases you need explicit control over the object disposal. This is relevant when an object represents a system resource, such as a file handle or a network socket. In these cases C# provides you with the *dispose pattern* and the ``using`` statement. .. tip:: To learn more about how to use objects that utilize the *dispose pattern*, see Microsoft documentation on the subject: `Using objects that implement IDisposable `_ Let us look at a quick example of opening a ``FileStream`` in C#: .. code:: csharp public void SomeMethod() { var file = new System.IO.FileStream("somefile.txt", System.IO.FileMode.Append); // write some data to file // I am done here, but forget to close the file handle! } Obviously, we forget to *close* the file handle. The garbage collector will eventually dispose and *close* our handle, when it collects our ``file`` object. But we cannot know when this happens. Worse, even if we remember to call the *close* method at the end of our function, we are still at risk. Exceptions thrown from our code or from code we call, will cause an early exit from our function, bypassing any ``close`` call, at the bottom! To mitigate this, C# has the ``using`` statement. The ``using`` statement ~~~~~~~~~~~~~~~~~~~~~~~ This statement ensures that an object exists only inside a single context. That is, as soon as the defining scope is exited, the object is disposed immediately. Let us modify the example from above, to use the ``using`` statement: .. code:: csharp public void SomeMethod() { using (var file = new System.IO.FileStream("somefile.txt", System.IO.FileMode.Append)) { // write some data to file // throw exceptions from here } // I am done here, but forget to close the file handle! } Now we are certain that our file handle is closed and freed, as soon as the using-scope is exited. No matter if our function runs to completion, or if an early exit is caused by an exception. When you work with objects returned to you from Image- and CameraSDK, you *must always* ensure these are properly disposed. Best practice is to utilize the ``using`` statement. Disposable Objects used in SDKs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Phase One SDK's internals are written in C, and our C# API interfaces to these C functions. This means that data passed to you, like *LiveView* image frames or in-memory bitmap images, might be allocated by the C runtime memory allocator. In C# terms we say that these objects reside in *unmanaged memory* and are not subject to the C# garbage collector. We could copy the objects from *unmanaged memory* into *managed memory*, that the garbage collector controls. However, that would have a significant performance and RAM usage penalty. Therefore, Camera- and ImageSDK provides you with C# objects, that references the raw *unmanaged memory*. .. note:: All image objects returned by CameraSDK reside in *unmanaged memory*. However, in ImageSDK, only image objects of type ``HugeBitmapImage`` have data that reside in *unmanaged memory*. Even if a data object does not use *unmanaged memory*, it is still good practice to use the *dispose pattern*, if the object implements ``IDisposable``. E.g. a bitmap image returned by ImageSDK can be very large, and would hog memory if not freed immediately after use. The NativeMemoryRef Class ^^^^^^^^^^^^^^^^^^^^^^^^^ The image data referenced in both ``IIQImageFile``, ``LiveViewImage`` and ``HugeBitmapImage`` classes, reside in *unmanaged memory*. You access this image data using the ``Data`` accessor, on both classes. The ``Data`` accessor is of type ``NativeMemoryRef``, which is the wrapper we use in our SDKs to access the *unmanaged memory*. ``NativeMemoryRef`` is a subclass of ``System.IO.Stream``, and you must use the .NET *stream* API's to access the referenced data. By utilizing the *stream* functionality, we do *not* need to copy data into *managed memory*, but are able to work with it directly in *unmanaged memory*. All these classes (``IIQImageFile``, ``LiveViewImage``, ``HugeBitmapImage`` and ``NativeMemoryRef``) implements the *dispose pattern*, meaning you should use them with the ``using`` statement. This will ensure their referenced memory are correctly dereferenced, and can be deallocated by the C based internals. Avoid using the ToArray Method ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In your application, you would probably like to write captured image to disk. When we receive an ``IIQImageFile`` object, a quick and dirty way to write its content to disk is: .. code:: csharp using (IIQImageFile iiqImage = camera.WaitForImage()) { System.IO.File.WriteAllBytes(iiqImage.FileName, iiqImage.Data.ToArray()) } This code correctly disposes the image object as soon as it is written to disk. However, the ``ToArray`` function implicitly copies all the image data from *unmanaged memory* into *managed*. This means we have a single image residing in memory twice! This is probably not what you want. Using the *stream* API's you can write directly from *unmanaged memory* to disk. This example uses the ``CopyTo`` method to write the image to a file, without any extraneous copying: .. code:: csharp using (IIQImageFile iiqImage = cameraData.mCamera.WaitForImage()) { using (var file = new FileStream(iiqImage.FileName, FileMode.Create)) { iiqImage.Data.CopyTo(file); } } If you intent to write LiveView frames to disk, the exact same approach can be used. .. tip:: In ImageSDK you would probably want to write your converted image to disk, in some popular format like Tiff. The built-in *TiffWriter* class handles writing the converted bitmap image into a file. It accounts for both scenarios, where data might be in *managed* or *unmanaged* memory. It does not do any unnecessary copying.