tMemSection 类:跟踪数千个指针(动态内存分配)






4.75/5 (11投票s)
演示如何使用几个类对内存块进行分组和组织。

引言
动态内存分配是专业 C++ 应用程序的需求。然而,这种做法有点容易出错,因为开发人员很多时候可能会忘记调用 free、HeapFree 或 delete 来释放先前分配的内存。
在本文中,我将介绍两个类来帮助您管理数百或数千个内存块:tMemSegment
和 tMemSection
。
tMemSection
封装了 Windows 操作系统支持的多个堆概念。它提供:
- 使用 Win32 堆函数进行动态内存分配。
- 按唯一 ID 分组和排序内存块。
- 多线程支持:类成员是线程安全的。
tMemSegment
仅仅是 tMemSection
对象的容器。您可以对许多 tMemSection
对象进行分组和排序。
目录
- 1. Windows 上的堆和 tlw_memory.h 概览
- 2. SampleApp 的作用是什么?
- 3. tMemSection 类成员
- 3.1 构造/析构
- 3.2 tMemSection::Alloc
- 3.3 tMemSection::AllocAndSet
- 3.4 tMemSection::Count
- 3.5 tMemSection::FirstPtr
- 3.6 tMemSection::Free
- 3.7 tMemSection::FreeAll
- 3.8 tMemSection::Get 和 GetAt
- 3.9 tMemSection::Grow
- 3.10 tMemSection::NextPtr
- 3.11 tMemSection::Ptr
- 3.12 tMemSection::PtrSize
- 3.13 tMemSection::Set 和 SetAt
- 3.14 tMemSection::TotalSize
- 3.15 tMemSection::operator=
- 4. tMemSegment 类成员
- 5. tMemPtr 结构体
- 6. 结论
1. Windows 上的堆和 tlw_memory.h 概览
在 Windows 上运行的每个进程都有一个系统提供的默认堆——也称为进程堆。任何进程都从其自己的进程堆动态分配内存。Windows 允许开发人员使用 堆函数创建额外的堆以提高进程性能。每个额外的堆是调用进程地址空间中一个或多个页面的一个区段。
因此,tMemSection
类的每个实例都对应于进程的一个新堆。
tMemSection
的所有功能都在 tlw_memory.h 中。这意味着您只需在 Win32 或 MFC 项目中 #include 它即可开始使用。下表显示了 tlw_memory.h 的内容(类和类型)及其简要描述。
类型 | 它是什么 |
tMemExceptionCode | tMemSection 和 tMemSegment 使用的所有可用异常代码的枚举。 |
tMemException | 成员函数引发的异常对象。 |
tSyncObj | 提供同步的简单对象。它由 tMemSection /tMemSegment 的实例使用,以保证线程安全访问。 |
tMemPtr | 表示指针信息的类型。 |
tMemPtrID | 用于创建内存块 ID 的类型。 |
tMemSection |
处理动态内存使用的类。 |
tMemSegment |
实现 tMemSection 对象容器的类。 |
1.1 使用 tlw_memory.h 时避免 MFC 编译错误
您会注意到 tMemSection
和 tMemSegment
使用 STL map 和 set 类型来分组和排序指针信息。如果您曾经尝试将 STL 与 MFC 一起使用,您可能会遇到一些难看的编译错误。
好吧,当我尝试在调试模式下编译我的 SampleApp 时,我不得不处理一个恼人的错误:
c:\program files\microsoft visual studio 8\vc\include\xtree(1317) : error C2061: syntax error : identifier '_Wherenode'
每次我切换到调试配置时,都会发生错误 C2061。花了一些时间才意识到错误的原因是一个 #define
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
DEBUG_NEW
是 MFC 调试工具箱的一部分。它重新定义了 new 运算符,这在使用 STL 时会导致问题。因此,简单的解决方案是:
#include "..\shared\tlw_memory.h" // include always before DEBUG_NEW
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//#include "..\shared\tlw_memory.h" // Ops! Wrong place ...
所以,请记住在 DEBUG_NEW
定义之前包含 tlw_memory.h 以避免问题。明白了吗?
2. SampleApp 的作用是什么?
SampleApp (图 1) 使用了 tMemSection
和 tMemSegment
类的一些功能。其目的是演示如何使用多个堆(或区段)来提高应用程序性能,或者至少使源代码更清晰。
SampleApp 分两步运行:
- 第 1 步:读取用户选择路径中的所有文件,并将文件信息保存在两个区段(或堆)中。内存信息如列表 1 所示。
- 第 2 步:将先前保存在这两个区段中的所有信息传输到列表 2。
查看 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
和 tMemSegment
位于 TLibWin
命名空间中。因此,您应该始终在访问它们之前输入 using namespace TLibWin
。
这三个定义是用于命名和排序 tMemSegment
容器中的 tMemSection
的 ID。
现在查看 SampleAppDlg.cpp 中 CSampleAppDlg::OnInitDialog
函数:
vg_memory.Add(MEM_TMP_DATA, tMemSection()); // temporary data - general use
vg_memory.Add(MEM_FILE_INFO, tMemSection()); // keep WIN32_FIND_DATA struct for files
vg_memory.Add(MEM_FILE_PATH, tMemSection()); // keep path for files
您可以看到正在实例化三个 tMemSection
对象。Add 函数的第一个参数指定用于访问这些 tMemSection
对象的 ID。
您可以在阅读本文的下一部分(描述 tMemSection
和 tMemSegment
操作)的同时自行探索 SampleApp 源代码的其余部分。
注意:SampleApp 可以扫描整个分区,但如果您没有以管理员权限登录,某些文件夹可能无法读取(例如,System32 文件夹)。在这种情况下,将不会扫描无法访问的文件夹。
3. tMemSection 类成员
tMemSection
负责分配/释放内存块,并将所有指针保存在一个容器中。这些指针可能按 ID 排序,也可能不按 ID 排序。
3.1 构造/析构
tMemSection()
tMemSection
构造一个新对象。每个 tMemSection
对象都关联一个堆。
~tMemSection()
释放所有已分配内存并销毁额外堆。
参数
无。
返回
如果构造成功,则返回 tMemSection
的新实例。
否则,将引发 tMemException(tcErrorCantCreateNewSection)
对象异常。
示例代码
using namespace TLibWin; // Do not forget this
...
// Two extra heaps are created
try
{
tMemSection sec1; // new heap with initial size = MEM_SECTION_SIZE
tMemSection *sec2 = new tMemSection(); // new heap with
// initial size = MEM_SECTION_SIZE
} catch ( tMemException e )
{
printf( "\nException while creating tMemSection object. code = %ld / system = %ld\n",
e.ecode, e.sys_error );
}
备注
MEM_SECTION_SIZE
定义堆的初始值——默认情况下为 1 兆字节。新堆根据内存分配进行增长。
另请参阅
3.2 tMemSection::Alloc
LPVOID Alloc(DWORD _size, tMemPtrID _id = tMemPtrID(tcNoId))
分配 _size
字节的内存。
参数
参数 | 含义 |
_size [in, required] |
要分配的字节数。 |
_id [in, optional] |
一个唯一的 tMemPtrID 类型 ID,用于命名内存块。通过设置 ID,您无需保存返回的内存块指针,并且可以随时通过提供 ID 来检索该指针。tMemSection::tcNoId 表示未传递 ID。 |
返回
如果调用成功,则返回指向内存块的新指针。
否则,根据调用结果,可能会引发以下两种异常之一:
tMemException(tcErrorCantAllocateMemory)
:如果分配失败。tMemException(tcErrorPointerIDAlreadyExists)
:如果传递了重复的 ID。
示例代码
try
{
tMemSection sec1; // new heap with initial size = MEM_SECTION_SIZE
...
LPVOID ptr1 = sec1.Alloc(1024); // Getting an unamed pointer
LPVOID ptr2 = sec1.Alloc(1024, tMemPtrID(1)); // Getting a named pointer
...
} catch ( tMemException e )
{
printf( "\nException! code = %ld / system = %ld\n",
e.ecode, e.sys_error );
}
备注
_size
将向上取整到 MEM_CHUNK
的倍数,以最大程度地减少碎片。
另请参阅
3.3 tMemSection::AllocAndSet
LPVOID AllocAndSet(DWORD _size, LPVOID _data, DWORD _data_size, tMemPtrID _id = tMemPtrID(tcNoId))
分配 _size
字节的内存并将 _data
复制到其中。
参数
参数 | 含义 |
_size [in, required] |
要分配的字节数。 |
_data [in, required] |
要复制的缓冲区。 |
_data_size [in, required] |
_data 的大小。 |
_id [in, optional] |
一个唯一的 tMemPtrID 类型 ID,用于命名内存块。通过设置 ID,您无需保存返回的内存块指针,并且可以随时通过提供 ID 来检索该指针。tMemSection::tcNoId 表示未传递 ID。 |
返回
如果调用成功,则返回一个已用 _data
设置的新指针。
否则,根据调用结果,可能会引发以下三种异常之一:
tMemException(tcErrorCantAllocateMemory)
:如果分配失败。tMemException(tcErrorPointerIDAlreadyExists)
:如果传递了重复的 ID。tMemException(tcErrorInvalidArgument)
:如果_data
为 NULL 或_data_size
为 0。
示例代码
try
{
tMemSection sec1;
LPVOID ptr1 = sec1.Alloc(30);
// Not thread safe
memcpy( ptr1, "this is a test", sizeof("this is a test"));
// Thread safe operation
// Getting a named pointer
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 );
}
备注
_size
将向上取整到 MEM_CHUNK
的倍数,以最大程度地减少碎片。
如果 _data_size
> _size
,则内存块大小为 _data_size
。
另请参阅
Free, Ptr, PtrSize, Set, SetAt
3.4 tMemSection::Count
DWORD Count(void)
检索当前分配的内存块数量。
参数
无。
返回
内存块数量。
示例代码
DWORD total = sec.Count();
另请参阅
3.5 tMemSection::FirstPtr
BOOL FirstPtr(tMemPtr &_ptr)
开始内存块枚举。
参数
参数 | 含义 |
tMemPtr [out, required] | 或 tMemSection::tPointer 。包含指针信息的结构体。 |
返回
如果至少有一个内存块已分配并具有相应的 tMemPtr 信息,则为 TRUE。
否则返回 FALSE。
示例代码
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) );
备注
FirstPtr
和 NextPtr
是一种在您没有任何其他信息(既没有指针也没有 ID)时访问指针信息的方法。实际上,您可能永远不会使用它们。您必须将此成员函数与 NextPtr 一起使用。
另请参阅
3.6 tMemSection::Free
void Free(LPVOID _ptr)
void Free(tMemPtrID _id)
释放之前由 Alloc 和 AllocAndSet 成员函数分配的内存块。
参数
参数 | 含义 |
_ptr [in, required] |
由 Alloc 或 AllocAndSet 返回的内存块指针。 |
_id [in, required] |
命名内存块的 ID。 |
返回
无。
示例代码
tMemSection sec;
LPVOID ptr = sec.Alloc(1000);
LPVOID ptr2 = sec.Alloc(300, tMemPtrID(1)); // Allocates for further use
...
sec.Free(ptr);
sec.Free(tMemPtrID(1)); // or sec.Free(ptr2)
另请参阅
3.7 tMemSection::FreeAll
void FreeAll(BOOL _bFreeAtOnce = FALSE)
释放所有已分配的内存块。
参数
参数 | 含义 |
_bFreeAtOnce [in, optional] |
当为 TRUE 时,调用 HeapDestroy 而不调用 HeapFree。旧堆被销毁,并在操作期间创建一个新堆。当为 FALSE 时,内存块通过使用 HeapFree 一个接一个地释放。 |
返回
无。
示例代码
tMemSection sec1;
tMemSection sec2;
...
sec1.FreeAll(); // Free all memory blocks one by one
sec2.FreeAll(TRUE); // Free all memory blocks at once
备注
Destructor
调用 FreeAll(TRUE)
以提高性能。Heap API 允许您调用 HeapDestroy 而不调用 HeapFree 函数。
另请参阅
3.8 tMemSection::Get 和 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)
从命名内存块检索数据。
参数
参数 | 含义 |
_id [in, required] |
命名内存块的 ID。 |
_at [in, required] |
内存块中的字节位置。 |
_ret_data [out, required] |
指向接收内存块数据的缓冲区的指针。 |
_ret_data_size [in, required] |
_ret_data 缓冲区的大小。 |
返回
如果调用成功,_ret_data
被填充,并返回指向由 _id 引用的内存块的指针。
否则,根据调用结果,可能会引发以下三种异常之一:
tMemException(tcErrorPointerNotFound)
:如果_id
不存在。tMemException(tcErrorInvalidArgument)
:如果_ret_data
无效或_ret_data_size
为 0。tMemException(tcErrorOutOfRange)
:如果_ret_data_size
或_at+_ret_data_size
大于内存块的大小。
示例代码
// *** Producer -> Consumer Sample
#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;
}
备注
示例代码展示了一个生产者消费者应用程序。在输出中,Count 必须为 0 或 1。
在运行多线程应用程序时,使用 Get
/GetAt
和 Set
/SetAt
进行同步。内存块必须命名才能使用这些成员函数。
另请参阅
Set, SetAt, Alloc, AllocAndSet
3.9 tMemSection::Grow
LPVOID Grow(LPVOID _ptr, DWORD _bytes)
LPVOID Grow(tMemPtrID _id, DWORD _bytes)
增加内存块的 N _bytes
。
参数
参数 | 含义 |
_ptr [in, required] |
由 Alloc 或 AllocAndSet 返回的内存块指针。 |
_id [in, required] |
命名内存块的 ID。 |
_bytes [in, required] |
增加内存块的字节数。 |
返回
如果调用成功,则返回指向内存块的指针。
否则,根据调用结果,可能会引发以下两种异常之一:
tMemException(tcErrorPointerNotFound)
:如果 _id 或 _ptr 不存在。tMemException(tcErrorCantAllocateMemory)
:如果分配失败。
示例代码
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) );
}
备注
增加大小后,原始内存块内容保持不变。
新内存块大小也会向上取整到 MEM_CHUNK
,以最大限度地减少碎片。
另请参阅
3.10 tMemSection::NextPtr
BOOL NextPtr(tMemPtr &_ptr)
继续指针枚举。
参数
参数 | 含义 |
tMemPtr [out, required] | 或 tMemSection::tPointer 。包含指针信息的结构体。 |
返回
如果至少有两个内存块并且有相应的 tMemPtr 信息,则返回 TRUE。
否则返回 FALSE。
示例代码
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) );
备注
FirstPtr 和 NextPtr 是一种在您没有任何其他信息(既没有指针也没有 ID)时访问指针信息的方法。实际上,您可能永远不会使用它们。您必须将此成员函数与 FirstPtr 一起使用。
另请参阅
3.11 tMemSection::Ptr
LPVOID Ptr(tMemPtrID _id)
通过 ID 检索指向内存块的指针。
参数
参数 | 含义 |
_id [in, required] |
命名内存块的 ID。 |
返回
如果 ID 存在,则返回内存块的指针。
否则返回 NULL。
示例代码
#define MAIN_BUFFER 0x10
tMemSection g_sec;
void init(void)
{
g_sec.Alloc(16*1024, tMemPtrID(MAIN_BUFFER)); // Allocates buffer
...
}
...
void SendBuffer(void)
{
// Retrieves pointer to memory block by ID
BYTE *buf = (BYTE *)g_sec.Ptr(tMemPtrID(MAIN_BUFFER));
....
}
备注
命名内存块为您提供了更大的灵活性,因为您不必担心保存指针。
另请参阅
3.12 tMemSection::PtrSize
DWORD PtrSize(LPVOID _ptr, DWORD *_sys_size = NULL)
检索内存块的用户定义大小和系统定义大小(四舍五入到 MEM_CHUNK
大小)。
参数
参数 | 含义 |
_ptr [in, required] |
由 Alloc 或 AllocAndSet 返回的内存块指针。 |
__sys_size [out, optional] |
返回实际分配的内存块大小(四舍五入到 MEM_CHUNK 大小)。 |
返回
如果调用成功,则返回内存块的大小。如果 _sys_size
不为 NULL,则也返回四舍五入到 MEM_CHUNK
倍数的实际块大小。
否则返回 0。
示例代码
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);
备注
tMemSection
分配用户请求的字节大小。然而,为了最小化碎片,大小会向上取整到 MEM_CHUNK
的倍数。
另请参阅
3.13 tMemSection::Set 和 SetAt
LPVOID Set(tMemPtrID _id, LPVOID _data, DWORD _data_size)
LPVOID SetAt(tMemPtrID _id, DWORD _at, LPVOID _data, DWORD _data_size)
将数据设置到已命名的内存块。
参数
参数 | 含义 |
_id [in, required] |
命名内存块的 ID。 |
_at [in, required] |
内存块中的字节位置。 |
_data [out, required] |
指向用于设置内存块的缓冲区的指针。 |
_data_size [in, required] |
_data 缓冲区的大小。 |
返回
如果调用成功,则返回指向由 _id
引用的内存块的指针。
否则,根据调用结果,可能会引发以下三种异常之一:
tMemException(tcErrorPointerNotFound)
:如果_id
不存在。tMemException(tcErrorInvalidArgument)
:如果_data
无效或_data_size
为 0。tMemException(tcErrorOutOfRange)
:如果_data_size
或_at+_data_size
大于内存块的大小。
示例代码
另请参阅
3.14 tMemSection::TotalSize
DWORD TotalSize(DWORD *_sys_size = NULL)
检索由 tMemSection
对象分配的总内存。
参数
参数 | 含义 |
_sys_size [out, optional] |
返回实际分配的内存大小(四舍五入到 MEM_CHUNK 大小)。 |
返回
如果调用成功,则返回分配内存的总大小。如果 _sys_size 不为 NULL,则也返回四舍五入到 MEM_CHUNK
倍数的总内存实际大小。
否则返回 0。
示例代码
tMemSection sec;
DWORD sz1 = 0, sz2 = 0;
char *buf1 = (char *)sec.Alloc(1700);
char *buf2 = (char *)sec.Alloc(1300);
sz1 = sec.TotalSize(&sz2);
备注
TotalSize
返回所有内存块大小的总和。
另请参阅
3.15 tMemSection::operator=
operator
= 将所有内存块复制到另一个 tMemSection
对象。
示例代码
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() );
备注
operator=
的结果是一个目标对象,它包含相同数量的内存块,在不同的堆中具有相同的内容。示例代码输出如下:
图 2 - 示例代码输出
4. tMemSegment 类成员
tMemSegment
类提供了一个包含 1 到 N 个 tMemSection
对象的容器。tMemSection
对象按 DWORD 值排序。
4.1 构造/析构
tMemSegment()
tMemSegment
构造一个新对象。
~tMemSegment()
销毁所有 tMemSection
对象并释放所有内存。
参数
无。
返回
tMemSegment
的新实例。
示例代码
using namespace TLibWin; // Do not forget this
...
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);
}
另请参阅
4.2 tMemSegment::Add
void Add(DWORD _id, tMemSection &_section)
添加一个新的 tMemSection
对象。
参数
参数 | 含义 |
_id [in, required] |
命名 tMemSection 对象的 ID。 |
_section [in, required] |
一个 tMemSection 对象。 |
返回
如果调用成功,则添加对象。
否则,根据调用结果,可能会引发异常:
tMemException(tcErrorSectionIDAlreadyExists)
:如果 _id 已存在。
示例代码
tMemSegment sections;
tMemSection sec;
// Allocating 50 memory blocks
for ( DWORD ii = 0; ii < 50; ii++ )
sec.AllocAndSet(50, "0123456789", sizeof("0123456789"), tMemPtrID(ii));
// Object is added not the reference!
sections.Add(100, sec);
sec.FreeAll();
printf( "\nTotal memory blocks = %ld", sections.Section(100).Count() );
备注
示例代码阐明了一些要点。Add
不添加引用,而是添加整个 tMemSection
对象的副本。因此,示例代码的输出是:
内存块总数 = 50
另请参阅
4.3 tMemSegment::Clear
void Clear(void)
销毁所有 tMemSection
对象。
参数
无。
返回
无。
示例代码
另请参阅
4.4 tMemSegment::Count
DWORD Count(void)
检索 tMemSection
对象的数量。
参数
无。
返回
tMemSection
对象的总数。
示例代码
另请参阅
4.5 tMemSegment::Pointers
DWORD Pointers(void)
检索由所有 tMemSection
对象分配的总内存块。
参数
无。
返回
所有 tMemSection
对象分配的总内存块。
示例代码
另请参阅
4.6 tMemSegment::Remove
void Remove(DWORD _id)
销毁一个 tMemSection
对象。
参数
参数 | 含义 |
_id [in, required] |
命名 tMemSection 对象的 ID。 |
返回
如果调用成功,tMemSection
对象将被销毁。
否则,根据调用结果,可能会引发异常:
tMemException(tcErrorSectionNotFound)
:如果 _id 无效。
示例代码
try
{
tMemSegment sections;
tMemSection sec1;
tMemSection sec2;
// sec1 allocates 100 memory blocks
for ( DWORD ii = 0; ii < 100; ii++ )
sec1.AllocAndSet(25, "0123456789", sizeof("0123456789"), tMemPtrID(ii));
// sec2 allocates 100 memory blocks with the same contents of sec1
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 );
// Removes one of tMemSection objects
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);
}
备注
示例代码输出如下:
另请参阅
4.7 tMemSegment::Section
tMemSection
&Section(DWORD _id)
检索对 tMemSection
对象的引用。
参数
参数 | 含义 |
_id [in, required] |
命名 tMemSection 对象的 ID。 |
返回
如果调用成功,则返回 tMemSection
对象的引用。
否则,根据调用结果,可能会引发异常:
tMemException(tcErrorSectionNotFound)
:如果 _id 无效。
示例代码
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);
}
备注
示例输出与 Remove 示例相同。
另请参阅
4.8 tMemSegment::Size
DWORD Size(DWORD *_sys_size)
检索由所有 tMemSection
对象分配的总内存。
参数
参数 | 含义 |
_sys_size [out, optional] |
返回实际分配的内存大小。 |
返回
如果调用成功,则返回分配内存的总大小。如果 _sys_size
不为 NULL,则也返回四舍五入到 MEM_CHUNK
倍数的总内存实际大小。
否则返回 0。
示例代码
备注
Size 函数返回所有 tMemSection
对象的所有内存块大小的总和。
另请参阅
5. tMemPtr 结构体
tMemPtr
结构体内部用于组织内存块信息。您只能通过使用 FirstPtr/NextPtr 访问它。
成员 | 含义 |
BOOL indexed | 当为 TRUE 时,内存块具有 ID。 |
tMemPtrID id | 内存块的 ID。仅当 indexed 成员为 TRUE 时有效。 |
DWORD ptr | 指向内存块的指针。 |
DWORD user_size | 用户请求的大小。 |
DWORD system_size | 由 tMemSection 计算的实际大小。 |
6. 结论
我希望这些类对您有用。
享受,希望这有所帮助。
历史
- 2009 年 7 月 15 日:第一个版本