windows核心编程

《windows核心编程》 18章 堆

故事扮演 提交于 2020-04-07 03:13:25
堆的优缺点: 优点:让我们专心解决手头问题,不必理会分配粒度和页边界这类事情。 缺点:分配和释放内存块的速度比其他方式慢,而且也无法对物理存储器的调拨和撤销进行直接控制。 什么是堆: 堆就是一块预订的地址空间区域。刚开始,区域大部分页面都没以调拨物理存储器。随前我们不断的从堆中分配内存,堆管理器会给堆调拨越来越多的物理存储器。这些物理存储器都是从页交换文件中分配的。释放堆中的内存块时,堆管理器会撤销已调拨的物理存储器。 18.1 进程默认堆 进程初始化时,系统会在进程地址空间创建一个堆。这个堆被称为默认堆。我们可以创建应用程序使用/HEAP链接器开关来改变默认区域大小。 多个线程分配堆的时候是依次分配的。 GetProcessHeap()得到进程默认堆句柄 18.2 为什么要创建额外的堆 对组件进行保护 更有效的内存管理 局部访问 避免线程同步的开销 快整释放 18.3 如何创建额外堆 HANDLE HeapCreate(fdwOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize); 18.3.1 从堆中分配内存块 HeepAlloc(HANDLE hHeap,DWORD fdwFlags,SIZE_T dwBytes); 18.3.1 调整内存块大小 HeadReAlloc(…); 18.3.3 获得内存块大小 HeapSize(…)

《windows核心编程》- 线程栈

 ̄綄美尐妖づ 提交于 2020-04-07 03:10:47
当系统创建线程的时候,会为线程栈预订一块地址空间区域,并给该区域调拨一些物理存储器。默认会预订1MB的地址空间并调拨两个页面的存储器。但是在构建 应用程序的时候可以改变这个默认值 在构建应用程序的时候链接器会把栈的大小写入到exe和dll文件的pe文件头中,当创建线程的时候会根据PE文件头中的大小来预订空间区域。在调用CreateThread或_beginthreadex的时候开发人员可以指定需要在一开始就调拨的地址空间大小和存储器大小。 下面显示了一台页面大小为4KB的机器上线程栈的地址空间区域(基址为0x08100000 )。该线程栈的地址空间区域和所调拨给该区域的都具有PAGE_READWRITE保护属性。 在预订地址空间后,系统会给区域顶部的两个页面调拨物理存储器。在线程开始之前系统会把线程栈的指针指向最上面那两个页面的末尾。这个页面就是线程开始使用栈的地方。区域顶部往下的第二个页面被称为防护页面。随着调用的越来越多,调用树也越来越深,线程也需要越来越多的栈空间 当线程试图访问防护页中的内存时,系统会得到通知这时系统会先给防护页面下面的那个页面调拨存储器,接着去除当前防护页面的PAGE_GUARD保护属性标志,然后给刚调拨的存储页指定PAGE_GUARD保护属性标志。该项技术使得系统能够在线程需要的时候才增加栈存储器大小。如果线程的调用树 断加深

windows核心编程学习笔记(五.续)堆

廉价感情. 提交于 2020-02-22 11:45:57
堆(Heap)和栈(Stack)不同,堆是给进程用的,用来存储各个线程申请的内存块。 不能同时在堆上进行Alloc操作,这就意味这如果2个线程同时执行new操作,那么一个可以执行,另一个要等到这个执行完毕才可以执行new——否则的话,可能返回同一个地址,而线程还傻乎乎的以为是不同的呢。因此,如果想获取高效率而不出现问题(当然还有其他原因),那么可以另外创建一个堆来使用。使用函数 HeapCreate 来创建一个堆。 从堆中分配内存:HeapAlloc 改变已分配内存大小:HeapReAlloc 获取已分配内存块大小:HeapSize 释放已分配内存块:HeapFree 销毁堆:HeapDestroy 可是,此时使用new操作符,仍将在默认的堆上分配空间,我们需要在新的堆上来分配空间,此时需要重载对应类的new和delete操作符。 class CSomeClass { private : static HANDLE s_hHeap; static UINT s_uNumAllocsInHeap; // Other private data and member functions public : void * operator new (size_t size); void operator delete ( void * p); // Other public data and

Windows核心编程 --- 线程同步

匿名 (未验证) 提交于 2019-12-03 00:27:02
1.Interlocked系列函数:利用CPU实现,如InterlockedAdd就是lock xadd 指令来实现同步 2,关键段(CRITICAL_SECTION),利用事件内核对象: 利用关键段之前要先 InitializeCriticalSection (&g_cs)来初始化一个关键段,在不再使用的时候要利用 DeleteCriticalSection 中。如果有两个资源A,B,三个线程1,2,3,如果12线程访问A资源,13线程访问B资源,那么就要创建两个关键段并在1线程调用两次EntryCriticalSection 3,如果有一个线程已经在访问资源,则另一个线程调用EntryCriticalSection后会使用一个事件内核对象来把调用进程切换到等待状态。如果很长时间都不会返回,那么EntryCriticalSection就会超时并引发异常,另一个函数 则不会让线程进入等待状态,而是通过返回TRUE和FASLE来判断释放资源被占用。 4,SpainLock (旋转锁) , 旋转所就是通过一个while循环一直检测一个量是否被占用,这个时间会比进入内核设置内核事件短一些,所以在多处理器上可以旋转锁和关键段一起使用,在初始化时候调用 InitializeCriticalSectionAndSpainCount 5,Slim读写锁(SRWLock):

windows核心编程笔记-进程

匿名 (未验证) 提交于 2019-12-03 00:27:02
1.CreateProcess的第二参数如果是Unicode版本直接传入字符串常量会造成异常,因为CreateProcess会修改传递的命令行参数,如果传入的是ANSI版本,则不会,因为ANSI版本会先转换为UNICODE这会创建一个临时的副本,所以能够修改。 2.CreateProcess的命令行参数的命令行参数如果没有指定绝对路径就会按照一下顺序搜索可执行文件: 3.在CreateProcess时候可以指定LPSTARTUPINFOA结构为StartupInfoEx,并且指定dwCreateFlags为EXTENDED_STARTUPINFO_PRESENT,然后修改StartupInfoEx的lpAttributeList,这个结构体指针要用两次InitializeProcThreadAttributeList,第一次获取结构体大小,然后在堆上分配空间后再调用一次,初始化后调用UpdateProcThreadAttribute将第三个参数设置为PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,第四个设置为要设置的父进程句柄,这样就可以更改CreateProcess创建的进程的父进程信息了。代码如下: #include<windows.h> #include<TlHelp32.h> #include<stdio.h> DWORD