快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

澳门银河网址amyh的网站_酒文化网进入



对我来说写一篇博客真的不轻易,我是个实足的完美主义者,然则水平很一样平常,以是我会花上很多光阴去修补文章。大概文章并不能让你知足,假如你有任何的建议,任何的,我都异常等候你能奉告我。这篇文章仍旧是继承Windows Embedded CE Internals (2)内存部分。

从硬件视角看内存

从硬件上看,可作为内存的大年夜体分为RAM、ROM、Nand/Nor Flash(兼具RAM和ROM特点的混杂体)。

RAM 內存可以进一步分为静态随机存取存储器(SRAM)和动态随机存取存储器(DRAM)两大年夜类。SRAM具有快速造访的优点,但临盆资源较为昂贵,一个范例的利用是高速缓存。而DRAM因为具有较低的单位容量价格,以是被大年夜量的采纳作为系统的主存储器。

以下简单枚举一些RAM:

DRAM

SRAM

VRAM(Video RAM)

DDR SDRAM(Double Data Rate SDRAM)

DDRII(Double Data Rate Synchronous DRAM)

那么RAM、ROM、Flash有哪些差别?我在这里简单的总结一下:

1.RAM必要供电才能保存数据,而ROM、Flash都不必要。

2.内存中的代码能够直接被履行的条件是CPU能够随机读取这个内存里面的数据,RAM满意这个前提的,还满意这个前提的是ROM和Nor Flash(也便是XIP)。CPU要履行Nand Flash里面的代码时必须把这些代码Copy到RAM里面。

3.由于ROM只能被随机的读,以是法度榜样中可读/写的静态数据等必要Copy到RAM中,而可履行代码文本段、只澳门银河网址amyh的网站读静态数据等不会被Copy到RAM。

4.关于Nand Flash和Nor Flash的详细差别请看这里。

从操作系统视角看内存

假如你是操作系统,你若何加载模块(module,包孕可履行代码的Win32文件,主要包括EXE文件和DLL文件)到内存中?

回答这个问题要懂得如下内容:

1.操作系统加载EXE文件时与DLL文件的差别。

2.PE文件布局。Windows Embedded CE以及Windows Mobile的PE文件布局与Windows桌面操作系统上的相同。

我们一个个来办理。

当我们在文件浏览器中双击EXE文件或者经由过程CreateProcess、ShellExecuteEx等函数履行一个EXE法度榜样时,一个EXE的实例——进程将会孕育发生,首先系统将为这个EXE创建一个自力的进程空间,解析导入函数,此时会加载这些函数所在DLL文件到进程空间,假如这个DLL也有导入函数,那么也会加载这些函数所在DLL,然后初始化静态数据区,建立一个本地堆,然后创建一个主线程,着末跳转到EXE的进口点。可以参考源码:C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\loader.c

//------------------------------------------------------------------------------

// Helper function to create a new proces. Will NOT return if succeeds

//------------------------------------------------------------------------------

DWORD

CreateNewProcHelper(

LPProcStartInfo lppsi

)

{

PTHREADpth = pCurThread;

PPROCESSpprc = pActvProc;

e32_lite*eptr = &pprc->e32;

LPVOIDlpStack = NULL;

DWORDflags, entry, dwErr = 0, len;

LPCWSTRprocname = GetPlainName (lppsi->pszImageName);

LPCWSTRpCmdLine;

LPWSTRuptr;

PNAMEpAlloc;

LPBYTEpCurSP;

REGTYPE*pArgs;

DEBUGCHK (OwnLoaderLock (pprc));

eptr = &pprc->e32;

if (dwErr = LoadE32 (&pprc->oe, eptr, &flags, &entry, 0)) {

DEBUGMSG(1,(TEXT("ERROR! LoadE32 failed, dwErr = %8.8lx!\r\n"), dwErr));

return dwErr;

}

if (flags & IMAGE_FILE_DL澳门银河网址amyh的网站L) {

DEBUGMSG(1,(TEXT("ERROR! CreateProcess on DLL!\r\n")));

returnERROR_BAD_EXE_FORMAT;

}

if ((flags & IMAGE_FILE_RELOCS_STRIPPED) && ((eptr->e32_vbase e32_vbase > 0x400000))) {

DEBUGMSG(1,(TEXT("ERROR! No relocations - can't load/fixup!\r\n")));

return ERROR_BAD_EXE_FORMAT;

}

pprc->BasePtr = (flags & IMAGE_FILE_RELOCS_STRIPPED) ? (LPVOID)eptr->e32_vbase : (LPVOID)0x10000;

DEBUGMSG(ZONE_LOADER1,(TEXT("BasePtr is %8.8lx\r\n"),pprc->BasePtr));

len = (NKwcslen (procname) + 1) * sizeof(WCHAR);

// reserve/commit memory for the EXE

if (!VMAlloc (pprc, pprc->BasePtr, eptr->e32_vsize, MEM_RESERVE|MEM_IMAGE, PAGE_NOACCESS)

|| !(pAlloc = AllocName (eptr->e32_objcnt*sizeof(o32_lite)+len + 2))) { // +2 for DWORD alignment

return ERROR_OUTOFMEMORY;

}

// optimization for resoure loading - rebase resource rva

if (eptr->e32_unit[RES].rva) {

eptr->e32_unit[RES].rva += (DWORD) pprc->BasePtr;

}

pprc->o32_ptr = (o32_lite *) ((DWORD) pAlloc + 4);// skip header info

uptr = (LPWSTR) (pprc->o32_ptr + eptr->e32_objcnt);

memcpy (uptr, procname, len);

pprc->lpszProcName = uptr;

if (dwErr = LoadO32(&pprc->oe,eptr,pprc->o32_ptr,(ulong)pprc->BasePtr)) {

DEBUGMSG(1,(TEXT("ERROR! LoadO32 failed, dwerr = %8.8lx!\r\n"), dwErr));

return dwErr;

}

if (!(pprc->oe.filetype & FA_PREFIXUP)) {

if (!PageAble (&pprc->oe) && !Relocate(eptr, pprc->o32_ptr, (ulong)pprc->BasePtr)) {

return ERROR_OUTOFMEMORY;

}

}

// allocate stack

eptr->e32_stackmax = CalcStackSize(eptr->e32_stackmax);

if (!(lpStack = VMCreateStack (pprc, eptr->e32_stackmax))) {

return ERROR_OUTOFMEMORY;

}

pth->tlsNonSecure = TLSPTR (lpStack, eptr->e32_stackmax);

pCmdLine = lppsi->pszCmdLine? lppsi->pszCmdLine : L"";

DEBUGMSG (ZONE_LOADER1, (L"Initializeing user stack cmdline = '%s', program = '%s', stack = %8.8lx\r\n",

pCmdLine, pprc->lpszProcName, lpStack));

// Upon return of InitCmdLineAndPrgName, pCmdLine will be pointing to user accessible command line, and

// pCurSP is the user accessible program name. pCurSP is also the top of stack inuse

pCurSP = InitCmdLineAndPrgName (&pCmdLine, pprc->lpszProcName, lpStack, eptr->e32_stackmax);

InitModInProc (pprc, (PMODULE) hCoreDll);

LockLoader (g_pprcNK);

// load MUI if it exist

pprc->pmodResource = LoadMUI (NULL, pprc->BasePtr, eptr);

UnlockLoader (g_pprcNK);

AdjustRegions (pprc->BasePtr, &pprc->oe, eptr, pprc->o32_ptr);

pth->dwStartAddr = (DWORD) pprc->BasePtr + entry;

DEBUGMSG(ZONE_LOADER1,(TEXT("Starting up the process!!! IP = %8.8lx\r\n"), pth->dwStartAddr));

UnlockLoader (pprc);

(* HDModLoad) ((DWORD)pprc);

CELOG_ProcessCreateEx (pprc);

// setup arguments to MainThreadBaseFunc

pArgs = (REGTYPE*) (pCurSP - 8 * REGSIZE);

pArgs[0] = pth->dwStartAddr;// arg1 - entry point

pArgs[1] = (REGTYPE) pCurSP;// arg2 - program name (returned value form InitCmdLineAndPrgName)

pArgs[2] = (REGTYPE) pCmdLine;// arg3 - command line

pArgs[3] = (REGTYPE) hCoreDll;// arg4 - hCoredll

pArgs[4] = (REGTYPE) pprc->pmodResource;// arg5 - MUI DLL of EXE

pArgs[5] = (REGTYPE) ((PMODULE) hCoreDll)->pmodResource;// arg6 - MUI DLL of coredll

#ifdef x86

{

NK_PCR *pcr = TLS2PCR (pth->tlsNonSecure);

// terminate registration pointer

pcr->ExceptionList = 0;

// setup return address on stack

pArgs --;

*pArgs = 0;// return address set to 0

}

#endif

pth->tlsNonSecure[PRETLS_STACKBOUND] = (DWORD) pArgs & ~(VM_PAGE_SIZE-1);

// update thread info

pth->dwOrigBase = (DWORD) lpStack;

pth->dwOrigStkSize = eptr->e32_stackmax;

// notify PSL of process creation

NKPSLNotify (DLL_PROCESS_ATTACH, pprc->dwId, pth->dwId);

//

// if create suspended, we need to suspend ourselves before releasing the creator. Or

// there can be a race condition where the creator calls "ResumeTherad" before we suspend,

// and the result is that the thread will be suspended forever.

//

// It's safe to modify bPendSusp here for no-one, but kernel has a handle to this thread.

// and we know kernel will not suspend this thread for sure.

//

if (CREATE_SUSPENDED & lppsi->fdwCreate) {

pth->bPendSusp = 1;

}

// notify caller process creation complete

ForceEventModify (GetEventPtr (pprc->phdProcEvt), EVENT_SET);

// creator signaled, we can suspend here if needed

if (pth->bPendSusp) {

KCall ((PKFN) SuspendSelfIfNeeded);

CLEAR_USERBLOCK (pth);

}

// in case we got terminated even before running user code, just go straight to NKExitThread

if (GET_DYING (pth)) {

NKExitThread (0);

// never return

DEBUGCHK (0);

}

// update process state

pprc->bState = PROCESS_STATE_NORMAL;

// machine dependent main thread startup

DEBUGMSG (ZONE_LOADER1,(TEXT("CreateNewProcHelper: Switch to User code at %8.8lx!\r\n"), pth->dwStartAddr));

MDSwitchToUserCode ((FARPROC) MTBFf, pArgs);

DEBUGCHK (0);// never return

return 0;// keep compiler happy

}

DLL不能零丁履行,它只能被EXE或者其它DLL哀求加载,除了上面说的那种要领被加载(隐式加载)外,还可以应用LoadLibrary和LoadLibraryEx函数加载,这样要领叫显式加载。显式加载有很多好处,首先能够让我们直接应用DLL中的函数,还有一个好处可能大年夜多半人并不清楚。比如这段代码,你知道它不直接应用头文件的中供给的函数,而应用LoadLibrary的好处吗?

// Obtain a module handle to toolhelp.dll

HINSTANCE hKernel = LoadLibrary(_T("toolhelp.dll"));

if (!hKernel) {

MessageBox(NULL, L"Toolhelp.dll not found", L"TrayTaskList", MB_OK);

return 0;

}

// all processes currently in the system.

hProcessSnap = (HINSTANCE)CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if (hProcessSnap == (HANDLE)-1)

return 0;

让我们来简单看下PE文件布局:(你大概会问为什么要懂得PE文件布局,由于操作系统的loader模块是按照这个款式把模块加载到内存中的。大概你发明Windows的PE文件布局不敷好,你有更好的规划,让可履行文件加载的更快,当然我得说你异常的优秀,由于大年夜部分法度榜样员并不知道PE文件布局。)

PE文件是很古老的器械了,然则我们现在仍旧在应用,而且是Windows通用的。

PE文件布局的开始部分是一些Header,之后才是正文——由一些Section组成。

为了更方便懂得,我们应用map文件,map文件是,你可以从这里得到若何从map文件定位利用法度榜样Crash的措施,还可以涉猎《Debugging Applications》得到更多相关常识。

在Visual Studio的这个位置设置是否天生map文件:

下图是天生的map文件的截图:

PE文件主要分为5个Section:

Section 0001 is the text segment containing the executable code of the program. (可履行代码文本)

Section 0002 contains the read-only static data. (只读静态数据)

Section 0003 contains the read/write static data. (可读/写静态数据)

Section 0004 contains the fix-up table to support calls to other DLLs.(调用其它DLL的修正表)

Section 0005 is the resource section containing the application's resources, such as menu and dialog box templates.(资本)

这5个Section还可以进一步细分,比如:.bss段表示利用法度榜样的未初始化数据,包括所有函数或源模块中声明为static的变量。.rdata段表示只读的数据,比如字符串翰墨量、常量和调试目录信息。所有其它变量(除了呈现在栈上的自动变量)存储在.data段之中。这些一样平常是利用法度榜样或模块的全局变量。

现在澳门银河网址amyh的网站再看一下Windows Embedded CE 5.0用户态内存散播图:

我们把上图从0000 0000地址到03FF FFFF地址的散播再放大年夜一下:

现在你应该大年夜体知道EXE文件中各个Section在CE 5.0版本中大年夜体加载到内存的哪里了。CE 6.0系统相对位置与其相似,只是单个进程不再是32M的自力空间,而是1G的自力空间。

知道了系统若何加载EXE的,那么系统又是若何加载DLL的呢?系统如何包管DLL的重用?

着末顺带着再先容一下敕令dumpbin [options] [files]

我们常常必要查看EXE、DLL或者LIB文件的导入或者导出函数,对照方便的一个措施便是在Visual Studio自带的敕令行中应用dumpbin,比如查看刚天生的PortableExecute.exe的导入函数:

C:\Program Files\Microsoft Visual Studio 9.0\VC> D:

D:> cd D:\Windows Mobile\PortableExecute\PortableExecute\Windows Mobile 6 Professional SDK (ARMV4I)\Debug

D:\Windows Mobile\PortableExecute\PortableExecute\Windows Mobile 6 Professional SDK (ARMV4I)\Debug> dumpbin /imports PortableExecute.exe

假如你是操作系统,你会如何治理内存给利用法度榜样应用?

这个问题主要获得下面两个问题:

1.为什么Windows Embedded CE是基于页式的虚拟内存系统?(声明:文章提到的虚拟内存指的是虚拟地址空间,不是平日说的Page File。)

2.为什么应用Page Pool?

我们一个个来办理。

虚拟内存在1959年就被发现用来暗藏谋略机存储系统的分层布局,从而极大年夜地简化后续编程义务。然则它是如斯的常见,不多人会思虑它为什么会存在。假如你深刻的去懂得了,你会发明这项发现着实太棒了。更多请看美国乔治梅森大年夜学谋略机科学系网上教程《Virtual Memory Module》和Peter J. Denning 1970年颁发的论文《Virtual Memory 》(我坦白我只看了一点点)。

在文章Windows Embedded CE 6.0 Internals (2)中讲到,利用法度榜样等应用的是虚拟地址,操作系统应用MMU处置惩罚虚拟地址到物理地址的实时转换,这样很显着的一个好吃是隔离了利用法度榜样等与物理地址的详细实现。与Windows桌面操作系统比拟,基于Windows Embedded CE系统设备的物理内存实现更多样化(文章第一部分也可以看到)。就这一点来说Windows Embedded CE更迫切的必要被实现为基于虚拟内存的系统。

当然任何工作都有两面的,带来了物理内存实现抽象化好处的同时低落了寻址的效率。为了尽统统要领去增补就义的效率,微软又应用了静态地址映射、 Page Pool等技巧(这些技巧可不是微软发现的)。这便是为什么微软一些操作系统的内存系统都对照繁杂的缘故原由。当然Windows Embedded CE内存系统的设计比Windows桌面系统(比如Windows XP)简洁了很多。终究人家是嵌入式系统。

别的我再枚举一点页式虚拟内存带来的好处(信托你从操作系统道理课上也有打仗过):

(1). 隔离了不合进澳门银河网址amyh的网站程的地址空间,每个进程都有自己自力的页目录,进程切换时CPU切换现场,包括切换页目录。

(2). 供给更细腻的内存数据安然保护和治理,治理的粒度到一个页面大年夜小,这个页面的权限可所以只读、可读可写、可履行、可读可履行、可读可写可履行、 Guard(首次造访会导致STATUS_GUARD_PAGE非常)、不容许造访、不容许缓存(CPU不会高速缓存映射到这个区域的RAM页面)。

(3). 为了更有效的应用物理内存。

别的弥补一点常识,在Windows Embedded CE 6.0中页面大年夜小是4KB(今朝的嵌入式处置惩罚器大年夜多是4KB页面的),在早期的CE系统中这个大年夜小是1KB。虚拟内存区域对齐的界限是64KB,也便是说最小的分配粒度是64KB,每次都因此64KB的整数倍分配。提交的粒度是一个页面大年夜小。

可以参看C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\vm.c中的VMAlloc函数和DoVMAlloc函数:

//-----------------------------------------------------------------------------------------------------------------

//

// VMAlloc: main function to allocate VM.

//

LPVOID

VMAlloc (

PPROCESS pprc,// process

LPVOID lpvaddr,// starting address

DWORDcbSize,// size, in byte, of the allocation

DWORDfAllocType,// allocation type

DWORDfProtect// protection

)

{

DWORDdwAddr = (DWORD) lpvaddr;

DWORDdwEnd= dwAddr + cbSize;

DWORDdwErr= 0;

LPVOIDlpRet= NULL;

// verify arguments

if (!IsValidAllocType (dwAddr, fAllocType)// valid fAllocType?

|| ((int) cbSize // valid size?

|| !IsValidProtect (fProtect)) {// valid fProtect?

dwErr = ERROR_INVALID_PARAMETER;

DEBUGMSG (ZONE_VIRTMEM, (L"VMAlloc failed, invalid parameter %8.8lx, %8.8lx %8.8lx %8.8lx\r\n",

lpvaddr, cbSize, fAllocType, fProtect));

} else {

DWORD cPages;// Number of pages

// page align start address

dwAddr &= ~VM_PAGE_OFST_MASK;

cPages = PAGECOUNT (dwEnd - dwAddr);

lpRet = DoVMAlloc (pprc, dwAddr, cPages, fAllocType, fProtect, PM_PT_ZEROED, &dwErr);

}

KSetLastError (pCurThread, dwErr);

return lpRet;

}

//-----------------------------------------------------------------------------------------------------------------

//

// DoVMAlloc: worker function to allocate VM.

//

static LPVOID

DoVMAlloc(

PPROCESS pprc,// the process where VM is to be allocated

DWORD dwAddr,// starting address

DWORD cPages,// # of pages

DWORD fAllocType,// allocation type

DWORD fProtect,// protection

DWORD dwPageType,// when committing, what type of page to use

LPDWORD pdwErr// error code if failed

)

{

DWORD dwRet = 0;

DWORD cPageNeeded = cPages;

// if dwAddr == 0, must reserve first

if (!dwAddr) {

fAllocType |= MEM_RESERVE;

}

DEBUGMSG (ZONE_VIRTMEM, (L"DoVMAlloc - proc-id: %8.8lx, dwAddr = %8.8lx, cPages = 0x%x, fAllocType = %8.8lx, dwPageType = %8.8lx\r\n",

pprc->dwId, dwAddr, cPages, fAllocType, dwPageType));

if ((MEM_COMMIT & fAllocType)// commiting page

&& g_nStackCached// got some cached stacks

&& WillTriggerPageOut ((long) cPages)) {// the request will trigger a pageout.

// free all cached stacks

VMFreeExcessStacks (0);

}

if (LockVM (pprc)) {

dwRet = (fAllocType & MEM_RESERVE)

? DoVMReserve (pprc, dwAddr, cPages, 0, fAllocType)// reserving VM

: VMScan (pprc, dwAddr, cPages, &cPageNeeded, fProtect & VM_READWRITE_PROT);// not reserving, must be commiting. Check if

// the range to be commited is from a single reservation.

// count #of page needed to commit

if (!dwRet) {

*pdwErr = dwAddr? ERROR_INVALID_PARAMETER: ERROR_NOT_ENOUGH_MEMORY;

} else if (fAllocType & MEM_COMMIT) {

if (cPageNeeded && !HoldPages (cPageNeeded, FALSE)) {

*pdwErr = ERROR_NOT_ENOUGH_MEMORY;

} else {

VMCommitStruct vs = { PageParamFormProtect (fProtect, dwRet), dwPageType, FALSE };

// got enough pages, update entries

Enumerate2ndPT (pprc->ppdir, dwRet, cPages, 0, CommitPages, &vs);

if (vs.fFlush) {

InvalidatePages (pprc, dwRet, cPages);

}

}

}

UnlockVM (pprc);

if (*pdwErr && dwRet) {

// fail to commit enough pages

if (fAllocType & MEM_RESERVE) {

VERIFY (!VMRelease (pprc, dwRet, cPages));

}

dwRet = 0;

}

CELOG_VirtualAlloc(pprc, dwRet, dwAddr, cPages, fAllocType, fProtect);

} else {

*pdwErr = ERROR_INVALID_PARAMETER;

}

DEBUGMSG (ZONE_VIRTMEM||!dwRet, (L"DoVMAlloc - returns %8.8lx\r\n", dwRet));

return (LPVOID) dwRet;

}

虚拟的页面有3中状态:Free、Reserved、Committed,只有 Committed 的页面才真正映射到物理内存中,这便是为什么你应用 VirtualAlloc 函数有 MEM_COMMIT 和 MEM_RESERVE 的缘故原由。

看看来是虚拟内存的机制图,由于没找到Windows Embedded CE 6.0的,我就拿《Windows Internals》(Windows XP、2003等桌面系统)中截图的说事了。

2的10次方x2的10次方x2的12次方=2的32次方=4G寻址空间。由于页面大年夜小是4KB,以是页内索引(Byte index)必要12比特去记录,剩下的20比特索引分成一个10比特的页目录索引和一个10比特的页表索引,这样有效的低落了页目录和页表的大年夜小(各要 1KB?大年夜小就可以了)。

下图是阐明若何把虚拟内存翻译成实际的物理地址,CR3寄存器用于寄放进程页目录的物理地址,进程切换时CPU会改动这个寄存器的值。

这个图反映了若何对每个页面进行治理和保护的,在PFN中记录每个页面是否脏了、是否可读等信息。

这里是对每个Bit位的具体解释。

前面PE文件布局中涉及到的段式虚拟内存和这里的页式虚拟内存组成了段页式虚拟内存系统。

Page Pool

一些观点:

Pool is a collection of physical pages reserved for a specific purpose.

Loader is kernel function to load code pages.

File is kernel function to load and commit non-executable pages from a file.

Trimming is reducing the page pool size by discarding pages when active pool size is larger than the target size.

Target size is the normal size of the pool the pool manager will maintain.

Maximum size is the pool will never be allowed to exceed this size.

整个RAM会被分成3个部分:血色部分为Loader pool保留,黄色部分为File pool保留,剩下的为一样平常分配,比如:Heaps、Stacks、DLL R/W data、Page Pool use above Target level。

那么为什么要Page Pool呢?且听下回分化。

从利用法度榜样视角看内存

我得借鉴一下何宗键师长教师的图来阐明一澳门银河网址amyh的网站下,可以一清二楚,从下到上内存治理函数应用起来会加倍方便。

虚拟内存API

虚拟内存是最基础的内存类型。堆、栈这样的逻辑内存着实仍旧是调用底层的虚拟内存API来分配内存。而VirtualAlloc、VirtualFree、VirtualReSize等函数直接操作利用法度榜样的虚拟内存空间中的页面。

应用虚拟内存API有一个异常留意的问题,请看如下代码:

for (i = 0; i

你能看到问题吗?

别的其它一些API有:VirtualProtect、VirtualQuery、VirtualAllocEx、 VirtualProtectEx、VirtualQueryEx、VirualFreeEx,后面Ex扩展的主要多了一个HANDLE hProcess参数,为了操作另一个进程的内存,当然之前你的OpenProcess。你还可以应用 ReadProcessMemory 和 WriteProcessMemory 操作其它进程分配的内存块。

无意偶尔必要比页更小的粒度来操作内存,这时虚拟内存API显着满意不明晰,你可以斟酌堆API。然则应用堆会呈现碎片等问题,有一些技术可以只管即便避免这个问题的呈现。由于篇幅在此略过。别的留意Windows Embedded CE里面已经没全局堆了,诸如GlobalAlloc、GlobalFree、GlobalRealloc这样的函数都是经由过程宏映射为 LocalAlloc等API了。

本地堆相关API有:LocalAlloc、LocalFree、LocalReAlloc、LocalSize等。

自力堆相关API有:HeapCreate、HeapAlloc、HeapFree、HeapReAlloc、HeapSize、HeapDestroy、CeHeapCreate等。

线程创建时假如不指定,默认的大年夜小是64KB,由于栈高低各必要一个页面记录是否有溢出,以是可用的大年夜小事56KB。法度榜样中应防止过分递归等操作造成栈溢出。

利用法度榜样内存泄露问题及定位

看看维基对内存泄露的的解释:“在谋略机科学中,内存透露指因为纰漏或差错造成法度榜样未能开释已经不再应用的内存的环境。内存透露并非指内存在物理上的消掉,而是利用法度榜样分配某段内存后,因为设计差错,导致在开释该段内存之前就掉去了对该段内存的节制,从而造成了内存的挥霍。”

Application Verify是办理这个问题最常用的对象,介于这篇博客的篇幅太长,移到下篇文章中先容了。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: