[笔记]Windows核心编程《十四》探索虚拟内存

简介: Windows核心编程《十四》探索虚拟内存

系列文章目录



[笔记]Windows核心编程《一》错误处理、字符编码

[笔记]Windows核心编程《二》内核对象

[笔记]Windows核心编程《三》进程

[笔记]Windows核心编程《四》作业

[笔记]快乐的LInux命令行《五》什么是shell

[笔记]Windows核心编程《五》线程基础

[笔记]Windows核心编程《六》线程调度、优先级和关联性

[笔记]Windows核心编程《七》用户模式下的线程同步

[笔记]Windows核心编程《八》用内核对象进行线程同步

[笔记]Windows核心编程《九》同步设备I/O和异步设备I/O

[笔记]Windows核心编程《十一》Windows线程池

[笔记]Windows核心编程《十二》纤程

[笔记]Windows核心编程《十三》windows内存体系结构

[笔记]Windows核心编程《十四》探索虚拟内存

[笔记]Windows核心编程《十五》在应用程序中使用虚拟内存

[笔记]Windows核心编程《十六》线程栈

[笔记]Windows核心编程《十七》内存映射文件

[笔记]Windows核心编程《十八》堆栈

[笔记]Windows核心编程《十九》DLL基础

[笔记]Windows核心编程《二十》DLL的高级操作技术

[笔记]Windows核心编程《二十一》线程本地存储器TLS

[笔记]Windows核心编程《二十二》注入DLL和拦截API

[笔记]Windows核心编程《二十三》结构化异常处理


相关:


文章目录



   系列文章目录

   前言

   一、系统信息

       1.1 GetSystemInfo函数

       SYSTEM_INFO结构体

       1.2 IsWow64Process函数

       1.3 系统信息调用示例

   二、虚拟内存状态

       2.1 GlobalMemoryStatus函数

   三、NUMA 机器中的内存状态

       3.1 SMP

       3.2 NUMA

       3.3 GetNumaAvailableMemoryNode函数

       示例程序:虚拟内存状态

   四、确定地址空间的状态

       4.1 VMQuery函数

       4.2 示例程序虚拟内存映射


前言


参考

虚拟内存有三种状态:

   空闲(free) : 进程不能访问这种页面,此页面还没有被分配

   保留(reserve):这个页面被预定了。但是还未与物理内存映射,因此这里也是不能访问的

   提交(commit): 内存已经被分配了,并且也与物理存储器映射了,进程已经可以访问这里


虚拟内存映射的三种方式:


   private : 进程私有内存,不被其他进程所共享, 一般是堆,栈

   mapped: 从别的内存映射而来

   image : 从程序的PE映像映射而来,一般是映像的区段 虚拟内存的页面属性


简单使用虚拟内存:

int main()
{
    //MEM_FREE    空闲,没有被使用
    //MEM_RESERVE 保留,没有与物理地址映射
    //MEM_COMMIT  提交,与物理地址进行映射
    //1.申请虚拟内存空间
    LPVOID pBuff = VirtualAlloc(
        0,  //预定的地址,申请空间从这个地址开始
        1,  //申请空间的大小,默认对齐4kb
        MEM_RESERVE | MEM_COMMIT,  //预定并提交
        PAGE_READWRITE           //可写可读
    );
    //VirtualAllocEx 在其它进程中申请空间
    //2.使用它
    memcpy(pBuff, "hello", 6);
    //3.释放内存
    VirtualFree(pBuff, 1, MEM_FREE);
    //VirtualFree 在其它进程中释放空间
    //修改内存分页属性
    char * pName = (char*)"hello";
    DWORD dwOldProtect;
    VirtualProtect(
        pName,          //修改的内存地址
        1,              //修改的大小,会分页对齐
        PAGE_READWRITE, //修改后的新属性
        &dwOldProtect); //修改前的原始属性
    pName[0] = 'x';
    //VirtualProtectEx 修改目标进程内存属性
}


一、系统信息


1.1 GetSystemInfo函数

GetSystemInfo

获取当前系统信息。

获取准确的信息对于WOW64运行的应用程序,调用GetNativeSystemInfo函数。

void WINAPI GetSystemInfo(
  __out  LPSYSTEM_INFO lpSystemInfo
);


启动时系统会确认这些值是多少,因此每个进程只需要调用该函数一次就足够


SYSTEM_INFO结构体

typedef struct _SYSTEM_INFO {
  union {
    DWORD  dwOemId;
    struct {
      WORD wProcessorArchitecture;  处理器体系结构
      WORD wReserved;
    } ;
  } ;
  DWORD     dwPageSize;   //页面大小
  LPVOID    lpMinimumApplicationAddress;  //进程最小可用虚拟机地址
  LPVOID    lpMaximumApplicationAddress; //进程私有空间最大可用内存地址
  DWORD_PTR dwActiveProcessorMask;  //活动CPU掩码
  DWORD     dwNumberOfProcessors;  //CPU数量
  DWORD     dwProcessorType;
  DWORD     dwAllocationGranularity;  //分配粒度
  WORD      wProcessorLevel;
  WORD      wProcessorRevision;
} SYSTEM_INFO;


14-1 SystemInfo的与内存有关的成员


图片.png


14-2 SystemInfo的与内存无关的成员

图片.png


1.2 IsWow64Process函数

为了让32位应用程序也能在64位版本的Windows上运行,Microsoft提供了一个称为Windows 32-bit On Windows64-bit的模拟层,又称为WOW64。

当32位应用通过WOW64运行时,GetSystemInfo返回值和他在64位应用程序中所取得的值可能会有不同。例如在32位下SYSTEM_INFO结构的dwPageSize字段值是4KB而在64位下是8KB。


想要知道程序是否在WOW64上运行,可以调用:

WINBASEAPI
BOOL
WINAPI
IsWow64Process(
    _In_ HANDLE hProcess,
    _Out_ PBOOL Wow64Process
    );

hProcess:要查看的目标进程句柄。

Wow64Process:Wow64Process指向返回值,若运行在WOW64模式下返回TRUE。

也可以使用ShlWApi.h中定义的IsOs并传递OS_WOW6432来判断。返回TRUE 则运行在WOW64下。


1.3 系统信息调用示例

github地址


二、虚拟内存状态


2.1 GlobalMemoryStatus函数

GlobalMemoryStatus可以用来取得当前内存状态的动态信息

WINBASEAPI
VOID
WINAPI
GlobalMemoryStatus(
    _Out_ LPMEMORYSTATUS lpBuffer
    );


三、NUMA 机器中的内存状态


NUMA详情

3.1 SMP

所谓对称多处理器结构,是指服务器中多个CPU对称工作,无主次或从属关系。各CPU共享相同的物理内存,每个 CPU访问内存中的任何地址所需时间是相同的。

图片.png

SMP服务器的主要特征是共享,系统中所有资源(CPU、内存、I/O等)都是共享的。也正是由于这种特征,导致了SMP服务器的主要问题,那就是它的扩展能力非常有限。对于SMP服务器而言,每一个共享的环节都可能造成SMP服务器扩展时的瓶颈,而最受限制的则是内存。由于每个CPU必须通过相同的内存总线访问相同的内存资源,因此随着CPU数量的增加,内存访问冲突将迅速增加,最终会造成CPU资源的浪费,使

CPU性能的有效性大大降低。


3.2 NUMA

图片.png

   由于SMP在扩展能力上的限制,人们开始探究如何进行有效地扩展从而构建大型系统的技术,NUMA就是这种努力下的结果之一。利用NUMA技术,可以把几十个CPU(甚至上百个CPU)组合在一个服务器内。NUMA服务器的基本特征是具有多个CPU模块,每个CPU模块由多个CPU(如4个)组成,并且具有独立的本地内存、I/O槽口等。由于其节点之间可以通过互联模块(如称为Crossbar

   Switch)进行连接和信息交互,因此每个CPU可以访问整个系统的内存(这是NUMA系统与MPP系统的重要差别)。显然,访问本地内存的速度将远远高于访问远地内存(系统内其它节点的内存)的速度,这也是非一致存储访问NUMA的由来。由于这个特点,为了更好地发挥系统性能,开发应用程序时需要尽量减少不同CPU模块之间的信息交互。利用NUMA技术,可以较好地解决原来SMP系统的扩展问题,在一个物理服务器内可以支持上百个CPU。比较典型的NUMA服务器的例子包括HP的Superdome、SUN15K、IBMp690等。

   每个CPU模块之间都是通过互联模块进行连接和信息交互,CPU都是互通互联的,同时,每个CPU模块平均划分为若干个Chip(不多于4个),每个Chip都有自己的内存控制器及内存插槽。


非统一内存访问(None-Uniform Memory Access,NUMA): 指机器中的cpu既能访问自己节点的内存也能访问其他节点的内存。


通常为了提高性能,尽量会使用自己节点的内存来支持物理存储器以提高内存访问的性能,但是如果没有足够的内存,windows也会使用外节点的内存来支持物理存储器。


3.3 GetNumaAvailableMemoryNode函数

如果要知道某个特定NUMA节点的内存数量,那么可以调用下面的函数:

WINBASEAPI
BOOL
WINAPI
GetNumaAvailableMemoryNode(
    _In_  UCHAR Node,
    _Out_ PULONGLONG AvailableBytes
    );

Node: 标识节点

AvailableBytes: 指向LONGLONG变量用来返回该节点的内存数量。


示例程序:虚拟内存状态

github地址


四、确定地址空间的状态


4.1 VMQuery函数

VirtualQuery 函数可以用于查询地址空间中的内存地址有关的特定信息(比如大小,存储器类型以及保护属性)。

WINBASEAPI
SIZE_T
WINAPI
VirtualQuery(
    _In_opt_ LPCVOID lpAddress,
    _Out_writes_bytes_to_(dwLength, return) PMEMORY_BASIC_INFORMATION lpBuffer,
    _In_ SIZE_T dwLength
    );

另一个函数允许一个进程来查询另外一个进程的内存信息。

WINBASEAPI
SIZE_T
WINAPI
VirtualQueryEx(
    _In_ HANDLE hProcess,
    _In_opt_ LPCVOID lpAddress,
    _Out_writes_bytes_to_(dwLength, return) PMEMORY_BASIC_INFORMATION lpBuffer,
    _In_ SIZE_T dwLength
    );
typedef struct _MEMORY_BASIC_INFORMATION {
    PVOID BaseAddress;
    PVOID AllocationBase;
    DWORD AllocationProtect;
    SIZE_T RegionSize;
    DWORD State;
    DWORD Protect;
    DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;


4.2 示例程序虚拟内存映射

github地址

相关文章
|
1月前
|
缓存 安全 Java
Java并发编程进阶:深入理解Java内存模型
【4月更文挑战第6天】Java内存模型(JMM)是多线程编程的关键,定义了线程间共享变量读写的规则,确保数据一致性和可见性。主要包括原子性、可见性和有序性三大特性。Happens-Before原则规定操作顺序,内存屏障和锁则保障这些原则的实施。理解JMM和相关机制对于编写线程安全、高性能的Java并发程序至关重要。
|
3天前
汇编语言(第四版) 实验一 查看CPU和内存,用机器指令和汇编指令编程
汇编语言(第四版) 实验一 查看CPU和内存,用机器指令和汇编指令编程
|
6天前
|
编解码 Windows
FFmpeg开发笔记(二十九)Windows环境给FFmpeg集成libxvid
XviD是开源MPEG-4视频编码器,与DivX相似但后者非开源。早期MP4常使用XviD或DivX编码,现已被H.264取代。在Windows上集成FFmpeg的XviD编解码库libxvid,需访问<https://labs.xvid.com/source/>下载源码,解压后在MSYS环境中配置、编译和安装。之后重新配置FFmpeg,启用libxvid并编译安装。详细步骤包括configure命令、make和make install。成功后,通过`ffmpeg -version`检查是否启用libxvid。更多音视频开发技术可参考《FFmpeg开发实战:从零基础到短视频上线》。
35 0
FFmpeg开发笔记(二十九)Windows环境给FFmpeg集成libxvid
|
11天前
|
算法 Linux 测试技术
Linux编程:测试-高效内存复制与随机数生成的性能
该文探讨了软件工程中的性能优化,重点关注内存复制和随机数生成。文章通过测试指出,`g_memmove`在内存复制中表现出显著优势,比简单for循环快约32倍。在随机数生成方面,`GRand`库在1000万次循环中的效率超过传统`rand()`。文中提供了测试代码和Makefile,建议在性能关键场景中使用`memcpy`、`g_memmove`以及高效的随机数生成库。
|
1月前
|
算法 Linux Windows
FFmpeg开发笔记(十七)Windows环境给FFmpeg集成字幕库libass
在Windows环境下为FFmpeg集成字幕渲染库libass涉及多个步骤,包括安装freetype、libxml2、gperf、fontconfig、fribidi、harfbuzz和libass。每个库的安装都需要下载源码、配置、编译和安装,并更新PKG_CONFIG_PATH环境变量。最后,重新配置并编译FFmpeg以启用libass及相关依赖。完成上述步骤后,通过`ffmpeg -version`确认libass已成功集成。
46 1
FFmpeg开发笔记(十七)Windows环境给FFmpeg集成字幕库libass
|
22天前
|
存储
8086 汇编笔记(二):寄存器(内存访问)
8086 汇编笔记(二):寄存器(内存访问)
|
23天前
|
Rust 安全 测试技术
使用Rust进行内存安全系统编程
【5月更文挑战第31天】Rust是一种保证内存安全的系统编程语言,通过所有权和借用系统防止内存错误,如内存泄漏和数据竞争。它的高性能、并发安全和跨平台特性使其在系统编程中占有一席之地。学习Rust涉及理解基本语法、所有权系统及使用标准库。通过案例分析,展示了如何在内存安全的前提下编写文件服务器。随着Rust的成熟,它在系统编程领域的应用前景广阔。
|
27天前
|
编解码 5G Linux
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
AVS3是中国首个8K及5G视频编码标准,相比AVS2和HEVC性能提升约30%。解码器libuavs3d支持8K/60P视频实时解码,兼容多种平台。《FFmpeg开发实战》书中介绍了在Windows环境下如何集成libuavs3d到FFmpeg。集成步骤包括下载源码、使用Visual Studio 2022编译、调整配置、安装库文件和头文件,以及重新配置和编译FFmpeg以启用libuavs3d。
41 0
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
|
1月前
|
编解码 Linux Windows
FFmpeg开发笔记(十一)Windows环境给FFmpeg集成vorbis和amr
在Windows环境下,为FFmpeg集成音频编解码库,包括libogg、libvorbis和opencore-amr,涉及下载源码、配置、编译和安装步骤。首先,安装libogg,通过配置、make和make install命令完成,并更新PKG_CONFIG_PATH。接着,安装libvorbis,同样配置、编译和安装,并修改pkgconfig文件。之后,安装opencore-amr。最后,重新配置并编译FFmpeg,启用ogg和amr支持,通过ffmpeg -version检查是否成功。整个过程需确保环境变量设置正确,并根据路径添加相应库。
47 1
FFmpeg开发笔记(十一)Windows环境给FFmpeg集成vorbis和amr
|
18天前
|
网络安全 Windows
windows Windows Defender彻底删除屏蔽后台启动占用内存 win10防火墙 windows10防火墙
windows Windows Defender彻底删除屏蔽后台启动占用内存 win10防火墙 windows10防火墙

热门文章

最新文章