.NET Core内存结构体系(Windows环境)底层原理浅谈
物理内存与虚拟内存
- 物理内存(Physical Memory)
定义:物理内存是计算机硬件中的实际RAM(如DDR5内存条),直接通过总线与CPU连接,用于临时存储运行中的程序和数据。 - 虚拟内存(Virtual Memory)
定义:由操作系统管理的抽象内存层,通过结合物理内存和磁盘空间(如页面文件或交换分区),为程序提供连续且独立的内存空间。
用户只需要与虚拟内存地址打交道,而无需关心数据到底分配在哪里

眼见为实

物理页4K对齐
在Windows系统下,以4K为最小粒度,这个单位叫做物理页,并以4K的整数倍分配内存。比如申请1k分配4k,申请5k分配8k
眼见为实
void page4k() {
for (int i = 0; i < 200; i++) {
//1k 的占用
LPVOID ptr = VirtualAlloc(NULL, 1024 * 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
printf("i=%d, 1k, address:%#0.8x \n", i + 1, ptr);
}
for (int i = 200; i < 400; i++) {
//5k 的占用
LPVOID ptr = VirtualAlloc(NULL, 1024 * 5, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
printf("i=%d, 5k, address:%#0.8x \n", i + 1, ptr);
}
getchar();
}
申请1k分配4k

申请5k分配8k

物理内存与虚拟内存如何映射?
Windows系统采用二叉树结构(5层)来实现高效映射。
举个例子,某个32bit的内存地址为:0x77b01a42,其二进制为:01110,11110,11000,00001,101001000010


前20位用来构建页表树,实现物理页的的高效映射后12位映射物理页的偏移量
操作系统以4K为一个单位对内存进行分组,4G内存=102410241024*4/(4/1024)=1048576物理页,如此庞大的物理页,,采用5层二叉树来提高索引效率
眼见为实:以notepad为例
任务管理:

Windbg:

可以看到非常明显的不同,任务管理器显示占用44.6mb内存,而windbg显示占用489.531mb内存,这是为什么呢?
答:显示逻辑不同,任务管理器显示的是Private WorkingSet,指的是物理内存的地址,即内存条上的内存,而Windbg是显示映射到的物理页,Commit指的是虚拟内存地址,这包括内存条上的内存,pagefile,image三种
眼见为实:可视化观察 虚拟地址=>物理地址
使用windbg进入内核态,这很重要,大家可以猜猜原因。
随便找一个字符串的内存地址

- 使用dp观察虚拟地址
- 使用!vtop 观察映射信息
- 使用!db观察物理地址
虚拟地址布局

眼见为实:空指针区与用户态区

windows/linux在默认情况下,会开启ASLR,需要关闭此技术才能复现。
ASLR 是一种针对缓冲区溢出攻击等内存攻击技术而设计的安全特性。在没有 ASLR 的情况下,程序加载到内存中的位置通常是固定的,攻击者可以预测程序中各种模块(如可执行文件、动态链接库等)的加载地址,进而利用这些固定地址来构造恶意代码进行攻击,比如在缓冲区溢出攻击中精准定位跳转地址来执行恶意指令。
而启用 ASLR 后,操作系统在每次启动程序时会随机化程序的内存布局,包括可执行文件、动态链接库、堆、栈等的加载地址,使得攻击者难以准确预测内存地址,大大增加了攻击的难度。
Reserved与Commit
- Reserved
在虚拟地址上申请一段内存空间,此时操作系统也会同步创建页表树,但此时并未映射到物理内存,此时对该虚拟内存的读写会抛异常 - Commit
给页表树调配真实的物理内存,此时才能正常写入
眼见为实:Reserved
void mem_reserved() {
LPVOID ptr = VirtualAlloc(NULL, 4 * 1024, MEM_RESERVE, PAGE_READWRITE);
*(int*)(ptr) = 10; //在首地址上写入内容。
printf("num=%d", *(int*)ptr);
}

眼见为实:Commit
void mem_commit() {
LPVOID ptr = VirtualAlloc(NULL, 4 * 1024, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
*(int*)(ptr) = 10; //在首地址上写入内容。
printf("num=%d", *(int*)ptr);
}

NT堆
NT堆是 Windows NT 内核引入的内存管理组件,主要负责进程内的堆内存分配与释放。在 Windows 系统里,进程可以使用 NT 堆来动态分配和管理内存,比如程序中使用 malloc()(C 语言)、new(C++) 等函数进行内存分配时,底层通常就依赖 NT 堆机制。
上面说到,VirtualAlloc方法它会一次性分配 64k 整数倍的内存段,内部对象按4k的内存页对齐.
如果让application直接操作VirtualAlloc,难免会造成大量的内存浪费。为了提高内存性能与使用效率,Windows又提供了一层抽象,以提供更细颗粒度的内存管理。它的名字叫做NT堆
- 在32bit平台上:8byte为一个分配粒度
- 在64bit平台上:16btye为一个分配粒度

- CRT堆:C运行时使用的堆,默认是对NT堆的简单封装
- 托管堆:用作特殊用途的,自行实现的一套内存池管理机制。比如GC堆
从图中可以看出,使用NT与否取决于程序员本身。完全可以绕过NT堆,直接使用VirtualAlloc来分配内存,只要你接收内存浪费。
眼见为实:GC堆,底层使用VirtualAlloc分配内存
点击查看代码
static void Main(string[] args)
{
var rand = new Random();
List<string> list = new List<string>();
for (int i = 0; i < 100000; i++)
{
var str = string.Join(",", Enumerable.Range(0, rand.Next(1, 1000)));
list.Add(str);
Console.WriteLine($"i={i},length={str.Length}");
}
Console.ReadLine();
}
在bp KERNELBASE!VirtualAlloc 下断点


眼见为实:CRT堆/NT堆,底层使用VirtualAlloc分配内存
点击查看代码
#include <iostream>
#include <Windows.h>
void crt_c() {
for (int i = 0; i < 10000000; i++) {
int* ptr = (int*)malloc(sizeof(int) * 1000);
*(ptr) = 10;
printf("第 %d 次分配 \n", i);
}
}
在 bp ntdll!NtAllocateVirtualMemory 下断点

.NET Core内存结构体系(Windows环境)底层原理浅谈的更多相关文章
- .net Core学习笔记:Windows环境搭建
1.安装 VS2015 Update3.如果已经安装了VS2015,但不是Update3版本,请在VS的工具 --> 扩展与更新 中执行update3的升级(大约需要2小时). 2..net C ...
- Java环境变量的操作系统原理[浅谈]
从知乎摘抄过来的文章,图没有复制过来,当作自己的笔记.其中我认为重要的部分(涉及操作系统的)已经加粗了. 本文源自:你应该知道的 Windows 环境变量 - 麓山南人的文章 - 知乎 https:/ ...
- Docker 基础底层架构浅谈
docker学习过程中,免不了需要学习下docker的底层技术,今天我们来记录下docker的底层架构吧! 从上图我们可以看到,docker依赖于linux内核的三个基本技术:namespaces.C ...
- Windows Azure HandBook (3) 浅谈Azure安全性
<Windows Azure Platform 系列文章目录> 2015年3月5日-6日,参加了上海的Azure University活动.作为桌长与微软合作伙伴交流了Azure相关的技术 ...
- 结构体的数据对齐 #pragma浅谈
之前若是有人拿个结构体或者联合体问我这个结构占用了多少字节的内存,我一定觉得这个人有点low, 直到某某公司的一个实习招聘模拟题的出现,让我不得不重新审视这个问题, 该问题大致如下: typedef ...
- JVM:内存结构
JVM:内存结构 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 程序计数器 虚拟机栈 本地方法栈 堆 方法区 直接内存 1. 程序计数器 1.1 定义 P ...
- jvm内存结构(一)(结构总览)
jvm内存结构:<Java虚拟机原理图解>3.JVM运行时数据区 程序计数器: ,是执行的字节码的行号指示器,记录的是正在执行的虚拟机字节码指令的地址. ,每个线程都有独立计数器,互不干扰 ...
- Java面试底层原理
面试发现经常有些重复的面试问题,自己也应该学会记录下来,最好自己能做成笔记,在下一次面的时候说得有条不紊,深入具体,面试官想必也很开心.以下是我个人总结,请参考: HashSet底层原理:(问了大几率 ...
- NHibernate从入门到精通系列(2)——NHibernate环境与结构体系
内容摘要 NHibernate的开发环境 NHibernate的结构体系 NHibernate的配置 一.NHibernate的开发环境 NHibernate的英文官方网站为:http://nhfor ...
- NHibernate从入门到精通系列——NHibernate环境与结构体系
内容摘要 NHibernate的开发环境 NHibernate的结构体系 NHibernate的配置 一.NHibernate的开发环境 NHibernate的英文官方网站为:http://nhfor ...
随机推荐
- php-fpm相关操作
php-fpm常用操作 一. php5.3.3之后使用新号方式控制php-fpm进程 INT, TERM 立即终止 QUIT 平滑终止 USR1 重新打开日志文件 USR2 平滑重启所有worker进 ...
- Ubuntu默认启动到字符界面
修改/etc/default/grub sudo cp /etc/default/grub /etc/default/grub.bak sudo chmod 0777 /etc/default/gru ...
- canvas(八)绘制图片和坐标转换
1.绘制图片 相关api及其参数:ctx.drawImage() 参数 说明 参数一 图片对象 参数二,三 可选,图片裁剪的基点(原图左上角为原点) 参数四,五 可选,图片裁剪区域的宽高(基于原图大小 ...
- uniapp 使用pinpa 持续化更新
安装依赖 npm i pinia npm i pinia-plugin-persistedstate 新建 index.ts import { createPinia } from 'pinia' i ...
- day02 计算机组成
day02 计算机组成 1.硬件 计算机硬件是指一些物理装置按照系统结构的要求构成一个有机整体为计算机软件运行提供物质基础 构成最基础的硬件有: CPU 内存 主板 IO设备 2.软件 计算机软件可以 ...
- 【C#】【平时作业】习题-7-继承、抽象与多态
相关概念 什么是继承 继承定义了如何根据现有类创先新类的过程 任何类都可以从另外一个类继承 一个派生出来的子类具有这个类的所有公共属性和方法 类的继承机制 创建新类所根据的基础类称为基类或父类,新建的 ...
- 冒泡排序------python实现
if __name__ == '__main__': ''' 算法描述 1.比较相邻的元素,更具大小交互位置 2.对每一对相邻元素作同样的工作,从开始第一队到结尾的最后一对,即可选出最大的数 3.所有 ...
- Qt/C++编写视频监控系统81-Onvif报警抓图和录像并回放
一.前言 视频监控系统中的图文警情模块,是通过Onvif协议的事件订阅拿到的,通过事件订阅后,设备的各种报警事件比如入侵报警/遮挡报警/越界报警/开关量报警等,触发后都会主动往订阅者发送,而且一般都是 ...
- Qt音视频开发21-通用硬解码
一.前言 硬件解码是图形芯片厂家提出的用GPU资源解码视频流的方案,与之相对的是软解,也就是传统的用CPU承担解码工作的方案:优点是效率高,功耗低.热功耗低,缺点是缺乏有力的支持(包括滤镜.字幕等), ...
- Soulmate
理想之所以是理想,也就是因为它只能存在于脑海中,天上月是天上月,水中花是水中花.但我们仍可以怀揣着对乌托邦的向往,所以,我对理想中的对象设想如下: 原来形容一个女子的眉眼,我总喜欢说眉眼如黛,眉如远山 ...