IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 虚拟内存的应用 -> 正文阅读

[网络协议]虚拟内存的应用

???????虚拟内存抽象使应用程序能够拥有一个独立而连续的虚拟地址空间,其通过页表与硬件的配合能够在对应用程序透明的前提下自动地进行虚拟地址到物理地址的翻译。除此之外,虚拟内存抽象还带来了其它的功能。

一、共享内存

共享内存允许通一个物理页在不同的应用程序中共享,如下图
在这里插入图片描述
???????应用程序A的虚拟页V1和应用程序B的虚拟页V2都被映射到物理页P,则物理页P是应用程序A和B的共享内存。此时程序A读取虚拟页V1和程序B读取虚拟页V2将得到相同的内容。互相也能看到对方所修改的内容。其中最重要的一个用途就是可以让不同的应用程序之间传递数据。基于共享内存的思想,操作系统又从中衍生出,写时拷贝、内存去重等功能。
下面是一个c++的例子
服务端:

#include <windows.h>
#include <iostream> 
using namespace std;

#define BUF_SIZE 4096

int main()
{
	// 定义共享数据
	char szBuffer[] = "锄禾日当午!";

	// 创建共享文件句柄 
	HANDLE hMapFile = CreateFileMapping(
		INVALID_HANDLE_VALUE,   // 物理文件句柄
		NULL,// 默认安全级别
		PAGE_READWRITE,   // 可读可写
		0,// 高位文件大小
		BUF_SIZE,// 低位文件大小
		L"ShareMemoryTy"   // 共享内存名称
		);

	// 映射缓存区视图 , 得到指向共享内存的指针
	LPVOID lpBase = MapViewOfFile(
		hMapFile,            // 共享内存的句柄
		FILE_MAP_ALL_ACCESS, // 可读写许可
		0,
		0,
		BUF_SIZE
		);

	// 将数据拷贝到共享内存
	strcpy((char*)lpBase, szBuffer);
	cout << "服务端:" << (char*)lpBase << endl;

	// 线程挂起等其他线程读取数据
	Sleep(20000);

	// 解除文件映射
	UnmapViewOfFile(lpBase);
	// 关闭内存映射文件对象句柄
	CloseHandle(hMapFile);
	return 0;
}

客户端:

#include <iostream>  
#include <windows.h>  
using namespace std;

#define BUF_SIZE 4096

int main()
{
	// 打开共享的文件对象
	HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, NULL, L"ShareMemoryTy");
	//cout << hMapFile << endl;

	if (hMapFile) {
		// 映射缓存区视图 , 得到指向共享内存的指针
		LPVOID lpBase = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
		// 将共享内存数据拷贝出来
		char szBuffer[BUF_SIZE] = { 0 };
		strcpy_s(szBuffer, (char*)lpBase);
		cout << "客户:" << szBuffer << endl;

		// 解除文件映射
		UnmapViewOfFile(lpBase);
		// 关闭内存映射文件对象句柄
		CloseHandle(hMapFile);

	}
	else {
		// 打开共享内存句柄失败
		cout << "打开共享失败!" << endl;
	}
	system("pause");
	return 0;
}

结果:
在这里插入图片描述

二、写时拷贝

???????写时拷贝技术允许应用程序A和应用程序B以只读的方式共享一段物理内存,一旦某个应用程序对该内存区域进行修改,就会触发缺页异常。注意,这里的缺页异常是否与违反权限导致的,不是之前所说的换页机制下的缺页异常是由于未映射导致的。在触发了缺页异常后,CPU同样会将控制流传递给操作系统预先设置的缺页异常处理函数,在该函数中操作系统会发现是缺页异常由于写了只读内存造成的,而且相应的内存区域又被系统标记为写时拷贝。于是操作系统会在物理内存中将缺页异常对应的物理页重新拷贝一份,并且将新拷贝的物理页以可读可写的方式重新映射给触发异常的应用程序,此后再恢复应用程序的执行。比如两个应用程序拥有很多相同的内存数据(比如加载了相同的动态链接库),如果把这些数据相同的内存页在物理内存中仅存一份,然后以只读的方式映射给两个应用程序,那么就能显著地节约物理内存。
接下来看例子:

#include <iostream>
#include <Windows.h>
#pragma warning (disable:4996)
using namespace  std;
class String
{
public:
	String(const char* pStr = "") //构造函数
		:_pStr(new char[strlen(pStr) + 4 + 1])//+4多创建的四个字节用来保存当前地址有几个对象
	{
		if (NULL == pStr)
		{
			*((int*)_pStr) = 1;//前4个字节用来计数
			_pStr += 4;//向后偏移4个字节
			*_pStr = '\0';
		}
		else
		{
			*((int *)_pStr) = 1;//前4个字节用来计数
			_pStr += 4;//向后偏移4个字节
			strcpy(_pStr, pStr);//拷贝字符串
		}
	}
	String(const String& s)//拷贝构造函数
		:_pStr(s._pStr)
	{
		++(*(int*)(_pStr - 4));//向前偏移4个字节将计数+1
	}
	~String()//析构函数
	{
		if (NULL == _pStr)
		{
			return;
		}
		else
		{
			if (--(*(int*)(_pStr - 4)) == 0)
			{
				delete[](_pStr - 4);
				_pStr = NULL;
			}
		}
	}
	//重载赋值运算符=
	String& operator=(const String& s)
	{
		if (_pStr != s._pStr)
		{
			if (--(*(int*)(_pStr - 4)) == 0)//释放旧空间
			{
				delete[](_pStr - 4);
				_pStr = NULL;
			}
			_pStr = s._pStr;//指向新空间
			++(*(int*)(_pStr - 4));//计数+1
		}
		return *this;
	}
	//重载下标访问操作符
	char& operator[](size_t t)
	{
		if (t >= 0 && t < strlen(_pStr))//下标非法判断
		{
			if ((*(int*)(_pStr - 4)) > 1)//多个对象指向同一块空间
			{
				char *pTemp = new char[strlen(_pStr) + 4 + 1];//开辟临时空间
				pTemp += 4;//向后偏移4个字节
				strcpy(pTemp, _pStr);//拷贝字符串
				--(*(int*)(_pStr - 4));//计数-1
				_pStr = pTemp;//将当前的对象指向临时空间
				*((int*)(_pStr - 4)) = 1;//将新空间的计数置为1
			}
			return _pStr[t];
		}
	}

	friend std::ostream & operator<<(std::ostream & out, String & A)
	{
		printf("%s  %p\n", A._pStr, A._pStr);
		return out;
	}
private:
	char *_pStr;
};
void FunTest()
{
	String s1("Hello world");
	std::cout << s1;

	String s2(s1);
	std::cout << s2;


	String s3 = s2;
	s3[3] = 'm';
	std::cout << s3;
}
int main()
{
	FunTest();

	system("pause");
	return 0;
}

结果:
在这里插入图片描述

三、内存去重

???????基于写时拷贝机制,操作系统进一步设计了内存去重的功能。操作系统可以定期地在内存中扫描具有相同内容的物理页,并且找到映射到这些物理页的虚拟页,然后只保留其中一个物理页,并将具有相同的内容的其它虚拟页都用写时拷贝的方式映射到这个物理页,然后释放其它物理页以供将来使用。该功能通常由操作系统主动发起。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-04-07 23:05:00  更:2022-04-07 23:06:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:51:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码