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 tMemSections objects. You can group and sort many tMemSections 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 tMemSections 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