Windows具有VirtualAlloc,它允许您保留连续的地址空间区域,但实际上不使用任何物理内存.稍后当您想要使用它(或其中的一部分)时,再次调用VirtualAlloc以提交先前保留页面的区域.
这实际上非常有用,但我想最终将我的应用程序移植到linux - 所以如果我以后无法移植它,我不想使用它.linux有办法做到这一点吗?
编辑 - 用例
我正在考虑分配4 GB或一些这样的虚拟地址空间,但一次只能提交64K.这将为我提供一种零拷贝方式来生成高达4 GB的阵列.这一点很重要,因为典型的两倍数组大小和副本会为非常大的数组引入看似随机的不可接受的延迟.
我睡不着!:)
我在Windows上有一个相当大的项目,遇到了一些堆损坏问题.我已阅读所有SO,包括这个好主题:如何调试堆损坏错误?但是没有什么比开箱即用更能帮助我了.Debug CRT
和BoundsChecker
检测到堆损坏,但地址总是不同的,并且检测点总是远离实际存储器重写.我没有睡到半夜,并制作了以下黑客:
DWORD PageSize = 0;
inline void SetPageSize()
{
if ( !PageSize )
{
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
PageSize = sysInfo.dwPageSize;
}
}
void* operator new (size_t nSize)
{
SetPageSize();
size_t Extra = nSize % PageSize;
nSize = nSize + ( PageSize - Extra );
return Ptr = VirtualAlloc( 0, nSize, MEM_COMMIT, PAGE_READWRITE);
}
void operator delete (void* pPtr)
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(pPtr, &mbi, sizeof(mbi));
// leave pages in reserved state, but free …
Run Code Online (Sandbox Code Playgroud) 我试图使用VirtualAlloc来保留和提交一块内存,然后再次扩展该块.不幸的是,它返回NULL并返回错误ERROR_INVALID_ADDRESS,尽管VirtualQuery说请求的地址范围是空闲的.这是我的代码:
void* allocation = VirtualAlloc(NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
void* desiredNextAllocation = (char*)allocation + 4096;
MEMORY_BASIC_INFORMATION info;
size_t memory_info = VirtualQuery(desiredNextAllocation, &info, sizeof(info));
void* extended = VirtualAlloc(desiredNextAllocation, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Run Code Online (Sandbox Code Playgroud)
第一个分配返回0x00000000000d0000.对VirtualQuery的调用导致'info'中的以下数据:
BaseAddress 0x00000000000d1000 void *
AllocationBase 0x0000000000000000 void *
AllocationProtect 0x00000000 unsigned long
RegionSize 0x00000000000ff000 unsigned __int64
State 0x00010000 unsigned long
Protect 0x00000001 unsigned long
Type 0x00000000 unsigned long
Run Code Online (Sandbox Code Playgroud)
我认为这意味着有0xff可用页面从0xd1000开始处于MEM_FREE状态.那么为什么我尝试在0xd1000提交页面失败?
我正在运行Windows 7,这是一个64位版本.
我已经阅读了几篇关于VirtualAlloc的StackOverflow帖子,但它们似乎都暗示这段代码应该像我对文档的理解一样工作.
我有一个小文件,我检查它并计算其中的字节数:
while(fgetc(myFilePtr) != EOF)
{
numbdrOfBytes++;
}
Run Code Online (Sandbox Code Playgroud)
现在我分配相同大小的虚拟内存:
BYTE* myBuf = (BYTE*)VirtualAlloc(NULL, numbdrOfBytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
Run Code Online (Sandbox Code Playgroud)
我现在想将文件的内容复制到 nyBuf 中。我该怎么做?
谢谢!
我正在编写一个 C++ 程序,它基本上适用于非常大的数组。在 Windows 上,我使用 VirtualAlloc 为我的数组分配内存。现在我完全理解了使用 VirutalAlloc 保留和提交内存的区别;但是,我想知道将内存逐页提交到保留区域是否有任何好处。特别是,MSDN ( http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx ) 包含对 MEM_COMMIT 选项的以下解释:
除非/直到实际访问虚拟地址,否则不会分配实际的物理页面。
我的实验证实了这一点:我可以保留和提交几 GB 的内存,而不会增加进程的内存使用量(如任务管理器中所示);只有当我实际访问内存时才会分配实际内存。
现在我看到很多例子认为应该保留大部分地址空间,然后逐页提交内存(或在一些更大的块中,取决于应用程序的逻辑)。然而,正如上面所解释的,在访问内存之前似乎并没有提交内存。因此,我想知道逐页提交内存是否有任何真正的好处。事实上,由于许多实际提交内存的系统调用,逐页提交内存实际上可能会减慢我的程序速度。如果我一次提交整个区域,我只需为一次系统调用付费,但内核似乎足够聪明,实际上只分配了我实际使用的内存。
如果有人能向我解释哪种策略更好,我将不胜感激。
我对VirtualAlloc感到困惑,
我们可以保留内存使用MEM_RESERVE,然后使用MEM_COMMIT提交它,但是我在下面两个函数之间使用时有点混淆:
m_pvData = VirtualAlloc(NULL, m_nBuffSize, MEM_COMMIT, PAGE_READWRITE);
m_pvData = VirtualAlloc(NULL, m_nBuffSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Run Code Online (Sandbox Code Playgroud)
第二种选择有什么好处?
我可以使用下面的函数来获取缓冲区:
void* pdata = VirtualAlloc(NULL, 64*1024*1024, MEM_COMMIT, PAGE_READWRITE);
if (pdata == NULL)
{
cout<<"Last error is "<<GetLastError()<<endl;
}
Run Code Online (Sandbox Code Playgroud)
没有错误
我需要使用VirtualAlloc/VirtualAllocEx?
一个例子,我发现的一个案例 - 如果我分配了4 GB的虚拟内存,那么如果我不使用所有这些,那么我不会花费物理内存,如果我调整我的数组,我不需要做新的分配旧数据并将其复制到新数组.
struct T_custom_allocator; // which using VirtualAllocEx()
std::vector<int, T_custom_allocator> vec;
vec.reserve(4*1024*1024*1024); // allocated virtual memory (physical memory is not used)
vec.resize(16384); // allocated 16KB of physical memory
// ...
vec.resize(32768); // allocated 32KB of physical memory
// (no need to copy of first 16 KB of data)
Run Code Online (Sandbox Code Playgroud)
如果我使用标准分配器,我需要在调整大小时复制数据:
std::vector<int> vec;
vec.resize(16384); // allocated 16KB of physical memory
// ...
vec.resize(32768); // allocated 32KB of physical memory
// and need to …
Run Code Online (Sandbox Code Playgroud) 重要提示:在此处投入太多时间之前,请向下滚动到"最终更新".事实证明,主要的教训是要注意单元测试套件中其他测试的副作用,并在得出结论之前始终将事物单独复制!
从表面上看,以下64位代码使用VirtualAlloc(总共4GByte)分配(并访问)一兆的4k页面:
const size_t N=4; // Tests with this many Gigabytes
const size_t pagesize4k=4096;
const size_t npages=(N<<30)/pagesize4k;
BOOST_AUTO_TEST_CASE(test_VirtualAlloc) {
std::vector<void*> pages(npages,0);
for (size_t i=0;i<pages.size();++i) {
pages[i]=VirtualAlloc(0,pagesize4k,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
*reinterpret_cast<char*>(pages[i])=1;
}
// Check all allocs succeeded
BOOST_CHECK(std::find(pages.begin(),pages.end(),nullptr)==pages.end());
// Free what we allocated
bool trouble=false;
for (size_t i=0;i<pages.size();++i) {
const BOOL err=VirtualFree(pages[i],0,MEM_RELEASE);
if (err==0) trouble=true;
}
BOOST_CHECK(!trouble);
}
Run Code Online (Sandbox Code Playgroud)
但是,在执行它时会增加Windows任务管理器中报告的"工作集" (并通过"峰值工作集"列中的"粘贴"值确认)从基线~200,000K(~200MByte)到超过6,000,000或7,000,000K (在64位Windows7上测试,也在ESX虚拟化的64位Server 2003和Server 2008上测试;遗憾的是我没有注意到观察到的各种数字的系统).
另一个非常相似的测试案例在同一个单元测试可执行文件中测试了一个超级4k的mallocs(后面是frees),并且在运行时只能扩展到预期的4GByte.
我不明白:VirtualAlloc是否有一些相当高的每分配开销?如果是这样,它显然是页面大小的一小部分; 为什么需要这么多额外的东西以及它的用途是什么?或者我误解了"工作集"报道实际上意味着什么?这里发生了什么?
更新:参考Hans的回答,我注意到在第二页访问中出现访问冲突失败,所以无论发生什么都不如分配到64K"粒度"那么简单.
char*const ptr = reinterpret_cast<char*>(
VirtualAlloc(0, 4096, MEM_RESERVE | MEM_COMMIT, …
Run Code Online (Sandbox Code Playgroud) 我想知道在Windows C编程中推荐哪种方法:使用malloc或Win32 HeapAlloc(可能是VirtualAlloc?)函数.
我已经阅读了有关malloc和HeapAlloc 的MSDN 内存管理函数文章和MSDN文章,但是他们没有说明应该使用哪一个以及在什么情况下.
如果malloc调用VirtualAlloc()函数来分配内存(分配最小4Kb),malloc如何为int分配4个字节?