Introduction
Dynamic memory allocation is a need in professional C++ applications. However, such practice is a bit error-prone because many times developer may forget that free, HeapFree or delete call to free previously allocated memory.
In this article I m going to introduce two classes to help you to manage hundreds or thousands of memory blocks : tMemSegment
and tMemSection
.
tMemSection
encapsulates the multiple heap concept supported by Windows OS. It offers:
- Dynamic Memory Allocation by using Win32 Heap Functions.
- Group and sort memory blocks by unique IDs.
- Multi-thread support: class members are thread safe.
tMemSegment
is nothing more than a container of tMemSection
s objects. You can group and sort many tMemSection
s objects.
Contents
1. Heaps on Windows and tlw_memory.h overview
Each process running on Windows has a default heap provided by the system - also called process heap. Any process allocates memory dynamically from its own process heap. Windows allows developer to create extra heaps to improve process performance by using Heap Functions. Each extra heap is a section of one or more pages in the address space of the calling process.
So, each instance of tMemSection
class corresponds to a new heap to the process.
All functionality of tMemSection
is into tlw_memory.h. That means you should only #include it in your Win32 or MFC projects to start using it. The following table shows the contents (classes and types) of tlw_memory.h and a brief description of them.
Type | What is it |
tMemExceptionCode | Enum for all available exception codes used by tMemSection and tMemSegment . |
tMemException | Exception object raised by member functions. |
tSyncObj | Simple object that provides synchronization. It is used by instances of tMemSection /tMemSegment to guarantee thread safe access. |
tMemPtr | Type that represents pointer information. |
tMemPtrID | Type used to create memory block ID. |
tMemSection | Class that handles dynamic memory usage. |
tMemSegment | Class that implements a container of tMemSection objects. |
1.1 Avoiding MFC compilation errors when using tlw_memory.h
You will notice tMemSection
and tMemSegment
use STL map and set types to group and sort pointer information. If you ever tried to use STL with MFC you probably faced some ugly compilation errors.
Well, I had to deal with an annoying error when trying to compile my SampleApp in debug mode:
c:\program files\microsoft visual studio 8\vc\include\xtree(1317) : error C2061: syntax error : identifier '_Wherenode'
Error C2061 happened to me every time I switched to Debug configuration. It took some time until I realized the error cause is a #define
:
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
DEBUG_NEW
is part of MFC debugging arsenal. It redefines new operator and that causes problems when using STL. Then, the simple solution is:
#include "..\shared\tlw_memory.h" // include always before DEBUG_NEW
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
So, remember to include tlw_memory.h before DEBUG_NEW
definition to avoid problems. Ok?
2. What does SampleApp do?
SampleApp (Figure 1) uses some features from tMemSection
and tMemSegment
classes. Its purpose is to demonstrate how to use multiple heaps (or sections) to improve applications performance or, at least, keep source code cleaner.
SampleApp is run in two steps:
- Step 1: Read all files in the path selected by user and saves file information in two sections (or heaps). Memory information is shown at List 1.
- Step 2: Transfer all information previously saved in those two sections to List 2.
Take a look at Globals.h:
using namespace TLibWin;
#define MEM_TMP_DATA 10
#define MEM_FILE_INFO 20
#define MEM_FILE_PATH 30
extern tMemSegment vg_memory;
tMemSection
and tMemSegment
are into TLibWin
namespace. So, you should always type using namespace TLibWin
before get access to them.
Those three defines are IDs to name and sort tMemSection
s into tMemSegment
container.
Now take a look at SampleAppDlg.cpp at function CSampleAppDlg::OnInitDialog
:
vg_memory.Add(MEM_TMP_DATA, tMemSection()); vg_memory.Add(MEM_FILE_INFO, tMemSection()); vg_memory.Add(MEM_FILE_PATH, tMemSection());
You see three tMemSection
objects being instantiated. The first argument in Add function specifies an ID to access those tMemSection
objects.
You can explore the rest of SampleApp source code by yourself while reading the next part of this article that describes tMemSection
and tMemSegment
operations.
Note: SampleApp can scan an entire partition but if you are not logged in with administrative privileges some folders may not be accessible for reading (for instance, System32 folder). In that case, inaccessible folders will not be scanned.
3. tMemSection Class Members
tMemSection
is responsible for allocating/freeing memory blocks keeping all pointers in a container. Those pointers might or not be sorted by an ID.
3.1 Construction/Destruction
tMemSection()
tMemSection
constructs a new object. Each object tMemSection
is associated a one heap.
~tMemSection()
Free all allocated memory and destroys extra heap.
Parameters
None.
Return
If construction succeeds a new instance of tMemSection
is returned.
Otherwise a tMemException(tcErrorCantCreateNewSection)
object exception is raised.
Sample Code
using namespace TLibWin;
...
try
{
tMemSection sec1; tMemSection *sec2 = new tMemSection(); } catch ( tMemException e )
{
printf( "\nException while creating tMemSection object. code = %ld / system = %ld\n",
e.ecode, e.sys_error );
}
Remarks
MEM_SECTION_SIZE
defines the initial value of the heap - 1 Megabyte by default. New heap is set to grow according to memory allocations.
See also:
Alloc, AllocAndSet
3.2 tMemSection::Alloc
LPVOID Alloc(DWORD _size, tMemPtrID _id = tMemPtrID(tcNoId))
Allocates _size bytes of memory.
Parameters
Parameter | Meaning |
_size [in, required] | Number of bytes to be allocated. |
_id [in, optional] | An unique ID type tMemPtrID to name memory block. By setting an ID allows you not to save returned memory block pointer and retrieve that pointer any time by informing ID. tMemSection::tcNoId means no ID is passed. |
Return
If call succeeds a new pointer to memory block is returned.
Otherwise one of these two exceptions can be raised depend upon result of call:
tMemException(tcErrorCantAllocateMemory)
: if allocations fails.tMemException(tcErrorPointerIDAlreadyExists)
: if a duplicated ID is passed.
Sample Code
try
{
tMemSection sec1;
...
LPVOID ptr1 = sec1.Alloc(1024); LPVOID ptr2 = sec1.Alloc(1024, tMemPtrID(1));
...
} catch ( tMemException e )
{
printf( "\nException! code = %ld / system = %ld\n",
e.ecode, e.sys_error );
}
Remarks
The _size
is rounded up to a multiple of MEM_CHUNK
to minimize fragmentation.
See also:
Free, Ptr, PtrSize
3.3 tMemSection::AllocAndSet
LPVOID AllocAndSet(DWORD _size, LPVOID _data, DWORD _data_size, tMemPtrID _id = tMemPtrID(tcNoId))
Allocates _size
bytes of memory and copy _data
to it.
Parameters
Parameter | Meaning |
_size [in, required] | Number of bytes to be allocated. |
_data [in, required] | Buffer to be copied. |
_data_size [in, required] | Size of _data. |
_id [in, optional] | An unique ID type tMemPtrID to name memory block. By setting an ID allows you not to save returned memory block pointer and retrieve that pointer any time by informing ID. tMemSection::tcNoId means no ID is passed. |
Return
If call succeeds a new pointer set with _data
is returned.
Otherwise one of these three exceptions can be raised depend upon result of call:
tMemException(tcErrorCantAllocateMemory)
: if allocations fails.tMemException(tcErrorPointerIDAlreadyExists)
: if a duplicated ID is passed.tMemException(tcErrorInvalidArgument)
: if _data
is NULL or _data_size
is 0.
Sample Code
try
{
tMemSection sec1;
LPVOID ptr1 = sec1.Alloc(30);
memcpy( ptr1, "this is a test", sizeof("this is a test"));
LPVOID ptr2 = sec1.AllocAndSet(30, "this is a test", sizeof("this is a test"));
} catch ( tMemException e )
{
printf( "\nException! code = %ld / system = %ld\n",
e.ecode, e.sys_error );
}
Remarks
The _size
is rounded up to a multiple of MEM_CHUNK
to minimize fragmentation.
If _data_size
> _size
then the memory block size is _data_size
.
See also:
Free, Ptr, PtrSize, Set, SetAt
3.4 tMemSection::Count
DWORD Count(void)
Retrieves the number of memory blocks currently allocated.
Parameters
None.
Return
Number of memory blocks.
Sample Code
DWORD total = sec.Count();
See also:
TotalSize
3.5 tMemSection::FirstPtr
BOOL FirstPtr(tMemPtr &_ptr)
Starts memory block enumeration.
Parameters
Parameter | Meaning |
tMemPtr [out, required] | or tMemSection::tPointer . Structure containing pointer information. |
Return
TRUE if there is, at least, one memory block allocated and the corresponding tMemPtr information.
Otherwise FALSE is returned.
Sample Code
tMemPtr pointer;
if ( sec1.FirstPtr(pointer) )
do
{
if ( pointer.user_size < 64 )
sec1.Grow( LPVOID(pointer.ptr), 64 - pointer.user_size );
} while ( sec1.NextPtr(pointer) );
Remarks
FirstPtr
and NextPtr
is a way to access pointers information when you do not have any other information - neither pointer nor ID. In fact, may be you never use them. You must use this member function together with NextPtr.
See also:
NextPtr
3.6 tMemSection::Free
void Free(LPVOID _ptr)
void Free(tMemPtrID _id)
Frees a memory block allocated previously by Alloc and AllocAndSet member functions.
Parameters
Parameter | Meaning |
_ptr [in, required] | Pointer to memory block returned by Alloc or AllocAndSet. |
_id [in, required] | ID that names a memory block. |
Return
None.
Sample Code
tMemSection sec;
LPVOID ptr = sec.Alloc(1000);
LPVOID ptr2 = sec.Alloc(300, tMemPtrID(1));
...
sec.Free(ptr);
sec.Free(tMemPtrID(1));
See also:
Alloc, AllocAndSet, FreeAll
3.7 tMemSection::FreeAll
void FreeAll(BOOL _bFreeAtOnce = FALSE)
Frees all allocated memory blocks.
Parameters
Parameter | Meaning |
_bFreeAtOnce [in, optional] | When TRUE HeapDestroy is called without calling HeapFree. Old hep is destroyed and a new HEAP is created during operation. When FALSE memory blocks are freed one by one by using HeapFree. |
Return
None.
Sample Code
tMemSection sec1;
tMemSection sec2;
...
sec1.FreeAll(); sec2.FreeAll(TRUE);
Remarks
Destructor
calls FreeAll(TRUE)
to improve performance. Heap API allows you call HeapDestroy without calling HeapFree function.
See also:
Alloc, AllocAndSet, Free
3.8 tMemSection::Get and GetAt
LPVOID Get(tMemPtrID _id, LPVOID _ret_data, DWORD _ret_data_size)
LPVOID GetAt(tMemPtrID _id, DWORD _at, LPVOID _ret_data, DWORD _ret_data_size)
Retrieves data from a named memory block.
Parameters
Parameter | Meaning |
_id [in, required] | ID that names a memory block. |
_at [in, required] | Byte position into memory block. |
_ret_data [out, required] | Pointer to a buffer that receives data from memory block. |
_ret_data_size [in, required] | Size of _ret_data buffer. |
Return
If call succeeds _ret_data
is filled and a pointer to memory block referenced by _id is returned.
Otherwise one of these three exceptions can be raised depend upon result of call:
tMemException(tcErrorPointerNotFound)
: if _id
does not exist.tMemException(tcErrorInvalidArgument)
: if _ret_data
is not valid or _ret_data_size
is 0.tMemException(tcErrorOutOfRange)
: if _ret_data_size
or _at+_ret_data_size
is greater than size of memory block.
Sample Code
#include "stdafx.h"
#include "tlw_memory.h"
using namespace TLibWin;
typedef struct __DATA
{
long count;
BOOL count_set;
} TDATA;
tMemSection mem;
DWORD WINAPI ThreadProducer(void)
{
TDATA reg;
while ( TRUE )
{
try
{
mem.Get( tMemPtrID(1), ®, sizeof(reg) );
if ( !reg.count_set )
{
reg.count_set = TRUE;
reg.count++;
mem.Set( tMemPtrID(1), ®, sizeof(reg) );
}
} catch ( tMemException e )
{
_tprintf( _T("\nProducer Exception (%ld) ... Aborting ...\n"), e.ecode );
exit(0);
}
}
return 0;
}
DWORD WINAPI ThreadConsumer(void)
{
TDATA reg;
while ( TRUE )
{
try
{
mem.Get( tMemPtrID(1), ®, sizeof(reg) );
if ( reg.count_set )
{
reg.count_set = FALSE;
reg.count--;
mem.Set( tMemPtrID(1), ®, sizeof(reg) );
}
} catch ( tMemException e )
{
_tprintf( _T("\nConsumer Exception (%ld) ... Aborting ...\n"), e.ecode );
exit(0);
}
}
return 0;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
TDATA reg = {0, FALSE };
mem.AllocAndSet( sizeof(TDATA), ®, sizeof(reg), tMemPtrID(1) );
::CreateThread( NULL, 0L, (LPTHREAD_START_ROUTINE)ThreadProducer, NULL, 0L, NULL );
::CreateThread( NULL, 0L, (LPTHREAD_START_ROUTINE)ThreadProducer, NULL, 0L, NULL );
::CreateThread( NULL, 0L, (LPTHREAD_START_ROUTINE)ThreadConsumer, NULL, 0L, NULL );
::CreateThread( NULL, 0L, (LPTHREAD_START_ROUTINE)ThreadConsumer, NULL, 0L, NULL );
while ( TRUE )
{
mem.Get( tMemPtrID(1), ®, sizeof(reg) );
_tprintf(_T("\nCount = %ld"), reg.count );
::Sleep(250);
}
return 0;
}
Remarks
The sample code shows a producer consumer application. In the output Count must be 0 or 1 only.
Use Get
/GetAt
and Set
/SetAt
to have synchronization when running a multi-thread applications. Memory blocks must be named to use these member functions.
See also:
Set, SetAt, Alloc, AllocAndSet
3.9 tMemSection::Grow
LPVOID Grow(LPVOID _ptr, DWORD _bytes)
LPVOID Grow(tMemPtrID _id, DWORD _bytes)
Increases N _bytes
of a memory block.
Parameters
Parameter | Meaning |
_ptr [in, required] | Pointer to memory block returned by Alloc or AllocAndSet. |
_id [in, required] | ID that names a memory block. |
_bytes [in, required] | Number of bytes to increase memory block. |
Return
If call succeeds a pointer to the memory block is returned.
Otherwise one of these two exceptions can be raised depend upon result of call:
tMemException(tcErrorPointerNotFound)
: if _id or _ptr does not exist.tMemException(tcErrorCantAllocateMemory)
: if allocation fails.
Sample Code
tMemSection sec;
char *buf = (char *)sec.Alloc(128);
DWORD sz = 0;
while ( (sz = strlen(buf)) < 4096 )
{
memset( &buf[sz], 'A', 127 );
buf = (char *)sec.Grow(buf, 128);
printf( "\nTotal Chars = %ld", strlen(buf) );
}
Remarks
The original memory block contents is preserved after size increasing.
New memory block size is also rounded up to MEM_CHUNK
to minimize fragmentation.
See also:
Alloc, AllocAndSet
3.10 tMemSection::NextPtr
BOOL NextPtr(tMemPtr &_ptr)
Continues pointer enumeration.
Parameters
Parameter | Meaning |
tMemPtr [out, required] | or tMemSection::tPointer . Structure containing pointer information. |
Return
TRUE if there is at least two memory blocks and the corresponding tMemPtr information.
Otherwise FALSE is returned.
Sample Code
tMemPtr pointer;
if ( sec1.FirstPtr(pointer) )
do
{
if ( pointer.user_size < 64 )
sec1.Grow( LPVOID(pointer.ptr), 64 - pointer.user_size );
} while ( sec1.NextPtr(pointer) );
Remarks
FirstPtr and NextPtr is a way to access pointers information when you do not have any other information - neither pointer nor ID. In fact, may be you never use them. You must use this member function together with FirstPtr.
See also:
FirstPtr
3.11 tMemSection::Ptr
LPVOID Ptr(tMemPtrID _id)
Retrieves pointer to a memory block by ID.
Parameters
Parameter | Meaning |
_id [in, required] | ID that names a memory block. |
Return
If ID exists then a pointer for a memory block is returned.
Otherwise NULL is returned.
Sample Code
#define MAIN_BUFFER 0x10
tMemSection g_sec;
void init(void)
{
g_sec.Alloc(16*1024, tMemPtrID(MAIN_BUFFER)); ...
}
...
void SendBuffer(void)
{
BYTE *buf = (BYTE *)g_sec.Ptr(tMemPtrID(MAIN_BUFFER));
....
}
Remarks
Name a memory block gives you more flexibility because you do not have to worry in saving the pointer.
See also:
Alloc, AllocAndSet
3.12 tMemSection::PtrSize
DWORD PtrSize(LPVOID _ptr, DWORD *_sys_size = NULL)
Retrieves both memory block sizes: user defined and system defined (MEM_CHUNK
size rounded) .
Parameters
Parameter | Meaning |
_ptr [in, required] | Pointer to memory block returned by Alloc or AllocAndSet. |
__sys_size [out, optional] | Returned the real allocated size of memory block (MEM_CHUNK size rounded) . |
Return
If call succeeds size of memory block is returned. If _sys_size
is not NULL then the real size of the block that is rounded up to a multiple of MEM_CHUNK
is returned too.
Otherwise 0 is returned.
Sample Code
tMemSection sec;
DWORD sz1 = 0, sz2 = 0;
char *buf = (char *)sec.Alloc(1700);
sz1 = sec.PtrSize(buf, &sz2);
buf = (char *)sec.Grow(buf,1024);
sz1 = sec.PtrSize(buf, &sz2);
Remarks
tMemSection
allocates size bytes requested by user. However, to minimize fragmentation, size is rounded up to a multiple of MEM_CHUNK
.
See also:
TotalSize
3.13 tMemSection::Set and SetAt
LPVOID Set(tMemPtrID _id, LPVOID _data, DWORD _data_size)
LPVOID SetAt(tMemPtrID _id, DWORD _at, LPVOID _data, DWORD _data_size)
Set data to a named memory block.
Parameters
Parameter | Meaning |
_id [in, required] | ID that names a memory block. |
_at [in, required] | Byte position into memory block. |
_data [out, required] | Pointer to a buffer to set memory block. |
_data_size [in, required] | Size of _data buffer. |
Return
If call succeeds a pointer to memory block referenced by _id
is returned.
Otherwise one of these three exceptions can be raised depend upon result of call:
tMemException(tcErrorPointerNotFound)
: if _id
does not exist.tMemException(tcErrorInvalidArgument)
: if _data
is not valid or _data_size
is 0. tMemException(tcErrorOutOfRange)
: if _data_size
or _at+_data_size
is greater than size of memory block.
Sample Code
See Get/GetAt sample code.
See also:
Get, GetAt
3.14 tMemSection::TotalSize
DWORD TotalSize(DWORD *_sys_size = NULL)
Retrieves total memory allocated by a tMemSection
object.
Parameters
Parameter | Meaning |
_sys_size [out, optional] | Returned the real allocated size of memory (MEM_CHUNK size rounded). |
Return
If call succeeds total size of allocated memory is returned. If _sys_size is not NULL then the real size of total memory that is rounded up to a multiple of MEM_CHUNK
is returned too.
Otherwise 0 is returned.
Sample Code
tMemSection sec;
DWORD sz1 = 0, sz2 = 0;
char *buf1 = (char *)sec.Alloc(1700);
char *buf2 = (char *)sec.Alloc(1300);
sz1 = sec.TotalSize(&sz2);
Remarks
TotalSize
returns the sum of all memory blocks sizes.
See also:
PtrSize
3.15 tMemSection::operator=
operator
= copies all memory blocks to another tMemSection
object.
Sample Code
tMemSection sec_src;
tMemSection sec_tar;
sec_src.AllocAndSet( 30, "pointer 1", sizeof("pointer 1") );
sec_src.AllocAndSet( 30, "pointer 2", sizeof("pointer 2"), tMemPtrID(1) );
printf( "\n sec_src has %ld memory blocks.", sec_src.Count() );
printf( "\n sec_tar has %ld memory blocks.", sec_tar.Count() );
sec_tar = sec_src;
sec_src.FreeAll();
printf( "\n\n sec_src has %ld memory blocks.", sec_src.Count() );
printf( "\n sec_tar has %ld memory blocks.", sec_tar.Count() );
Remarks
The result of operator=
is a target object that contains the same number of memory blocks with the same contents in a different heap. The sample code output is:
Figure 2 - Sample code output
4. tMemSegment Class Members
tMemSegment
class provides a container from 1 to N tMemSection
objects. tMemSection
objects are sorted by a DWORD value.
4.1 Construction/Destruction
tMemSegment()
tMemSegment
constructs a new object.
~tMemSegment()
Destroys all tMemSection
objects and free all memory.
Parameters
None.
Return
A new instance of tMemSegment
.
Sample Code
using namespace TLibWin;
...
tMemSegment sections;
try
{
sections.Add(0, tMemSection());
sections.Add(1, tMemSection());
sections.Add(2, tMemSection());
printf( "\n tMemSegment contains %ld sections", sections.Count() );
sections.Clear();
printf( "\n tMemSegment contains %ld sections", sections.Count() );
}
catch(tMemException e)
{
printf( "\nException code = %ld / system = %ld\n", e.ecode, e.sys_error );
exit(0);
}
See also:
Add, Section
4.2 tMemSegment::Add
void Add(DWORD _id, tMemSection &_section)
Adds a new object tMemSection
.
Parameters
Parameter | Meaning |
_id [in, required] | ID that names the tMemSection object. |
_section [in, required] | A tMemSection object. |
Return
If call succeeds object is added.
Otherwise an exception can be raised depend upon result of call:
tMemException(tcErrorSectionIDAlreadyExists)
: if _id already exists.
Sample Code
tMemSegment sections;
tMemSection sec;
for ( DWORD ii = 0; ii < 50; ii++ )
sec.AllocAndSet(50, "0123456789", sizeof("0123456789"), tMemPtrID(ii));
sections.Add(100, sec);
sec.FreeAll();
printf( "\nTotal memory blocks = %ld", sections.Section(100).Count() );
Remarks
Sample code makes some points clear. Add
does not add a reference but a copy of entire tMemSection
object. So, the output of sample code is:
Total memory blocks = 50
See also:
Section, Remove
4.3 tMemSegment::Clear
void Clear(void)
Destroys all tMemSection
objects.
Parameters
None.
Return
None.
Sample Code
See Constructor/Destructor sample code.
See also:
Add, Remove
4.4 tMemSegment::Count
DWORD Count(void)
Retrieves the number of tMemSection
objects.
Parameters
None.
Return
Total the tMemSection
objects.
Sample Code
See Constructor/Destructor sample code.
See also:
Add, Remove
4.5 tMemSegment::Pointers
DWORD Pointers(void)
Retrieves the total memory blocks allocated by all tMemSection
objects.
Parameters
None.
Return
Total memory blocks allocated by all tMemSection
objects..
Sample Code
See Remove sample code.
See also:
Add, Remove
4.6 tMemSegment::Remove
void Remove(DWORD _id)
Destroys a tMemSection
object.
Parameters
Parameter | Meaning |
_id [in, required] | ID that names the tMemSection object. |
Return
If call succeeds tMemSection
object is destroyed.
Otherwise an exception can be raised depend upon result of call:
tMemException(tcErrorSectionNotFound)
: if _id is not valid.
Sample Code
try
{
tMemSegment sections;
tMemSection sec1;
tMemSection sec2;
for ( DWORD ii = 0; ii < 100; ii++ )
sec1.AllocAndSet(25, "0123456789", sizeof("0123456789"), tMemPtrID(ii));
sec2 = sec1;
sections.Add(10, sec1);
sections.Add(11, sec2);
sec1.FreeAll();
sec2.FreeAll();
DWORD tuser = 0, tsystem = 0;
tuser = sections.Size(&tsystem);
printf( "\nTotal Memory Blocks: %ld\nTotal Size User/System: %ld bytes/%ld bytes",
sections.Pointers(), tuser, tsystem );
sections.Remove(10);
tuser = sections.Size(&tsystem);
printf( "\n\nTotal Memory Blocks: %ld\nTotal Size User/System: %ld bytes/%ld bytes",
sections.Pointers(), tuser, tsystem );
}
catch(tMemException e)
{
printf( "\nException code = %ld / system = %ld\n", e.ecode, e.sys_error );
exit(0);
}
Remarks
The sample code output is:
See also:
Add, Clear
4.7 tMemSegment::Section
tMemSection
&Section(DWORD _id)
Retrieves a reference to a tMemSection
object.
Parameters
Parameter | Meaning |
_id [in, required] | ID that names the tMemSection object. |
Return
If call succeeds tMemSection
object reference is returned.
Otherwise an exception can be raised depend upon result of call:
tMemException(tcErrorSectionNotFound)
: if _id is not valid.
Sample Code
try
{
tMemSegment sections;
sections.Add(10, tMemSection());
sections.Add(11, tMemSection());
for ( DWORD ii = 0; ii < 100; ii++ )
sections.Section(10).AllocAndSet(25, "0123456789", sizeof("0123456789"),
tMemPtrID(ii));
sections.Section(11) = sections.Section(10);
DWORD tuser = 0, tsystem = 0;
tuser = sections.Size(&tsystem);
printf( "\n Total Memory Blocks: %ld\n Total Size User/System: %ld bytes/%ld bytes",
sections.Pointers(), tuser, tsystem );
sections.Remove(10);
tuser = sections.Size(&tsystem);
printf( "\n Total Memory Blocks: %ld\n Total Size User/System: %ld bytes/%ld bytes",
sections.Pointers(), tuser, tsystem );
}
catch(tMemException e)
{
printf( "\nException code = %ld / system = %ld\n", e.ecode, e.sys_error );
exit(0);
}
Remarks
The sample output is identical to Remove sample.
See also:
Add, Remove
4.8 tMemSegment::Size
DWORD Size(DWORD *_sys_size)
Retrieves total memory allocated by all tMemSection
objects.
Parameters
Parameter | Meaning |
_sys_size [out, optional] | Returned the real allocated size of memory. |
Return
If call succeeds total size of allocated memory is returned. If _sys_size
is not NULL then the real size of total memory that is rounded up to a multiple of MEM_CHUNK
is returned too.
Otherwise 0 is returned.
Sample Code
See Remove sample code.
Remarks
Size function returns the sum of all memory blocks sizes of all tMemSection
objects.
See also:
Add, Remove
5. tMemPtr Structure
tMemPtr
structure is used internally to organize memory block information. You will only have access to it by using FirstPtr/NextPtr.
Member | Meaning |
BOOL indexed | When TRUE memory block has an ID. |
tMemPtrID id | ID of memory block. Only valid when indexed member is TRUE. |
DWORD ptr | Pointer to memory block. |
DWORD user_size | Size requested by user. |
DWORD system_size | Real size calculated by tMemSection . |
6. Conclusion
I hope these classes are useful to you.
Enjoy, hope this helps.
History
- 15 July, 2009: First version