- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我今天一直在 VC++ 2008 上研究内存映射,但我仍然没有完全理解如何使用它或者它是否适合我的目的。我的目标是快速读取一个非常大的二进制文件。
我有一个结构:
typedef struct _data
{
int number;
char character[512];
float *entries;
}Data;
多次写入文件。 “条目”变量是一个浮点小数数组。写入此文件后(10000 个数据结构,每个“条目”数组为 90000 个 float ),我尝试使用以下函数内存映射此文件,以便我可以更快地读取数据。这是我到目前为止所拥有的:
void readDataMmap(char *fname, //name of file containing my data
int arraySize, //number of values in struct Data
int entrySize) //number of values in each "entries" array
{
//Read and mem map the file
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hMapFile;
char* pBuf;
int fd = open(fname, O_RDONLY);
if(fd == -1){
printf("Error: read failed");
exit(-1);
}
hFile = CreateFile((TCHAR*)fname,
GENERIC_READ, // open for reading
0, // do not share
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no template
if (hFile == INVALID_HANDLE_VALUE)
{
printf("First CreateFile failed"));
return (1);
}
hMapFile = CreateFileMapping(hFile,
NULL, // default security
PAGE_READWRITE,
0, // max. object size
0, // buffer size
NULL); // name of mapping object
if(hMapFile == ERROR_FILE_INVALID){
printf("File Mapping failed");
return(2);
}
pBuf = (char*) MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_READ, // read/write permission
0,
0,
0); //Was NULL, 0 should represent full file bytesToMap size
if (pBuf == NULL)
{
printf("Could not map view of file\n");
CloseHandle(hMapFile);
return 1;
}
//Allocate data structure
Data *inData = new Data[arraySize];
for(int i = 0; i<arraySize; i++)inData[i].entries = new float[entrySize];
int pos = 0;
for(int i = 0; i < arraySize; i++)
{
//This is where I'm not sure what to do with the memory block
}
}
在函数的最后,内存被映射后,我返回了一个指向内存块“pBuf”开头的指针,我不知道该怎么做才能读回这个内存块进入我的数据结构。所以最终我想将这个内存块传输回我的 10000 数据结构条目数组。当然,我可能做错了......
最佳答案
处理内存映射文件实际上与处理任何其他类型的内存指针没有什么不同。内存映射文件只是一个数据 block ,您可以使用相同的名称从任何进程读取和写入它。
我假设您想将文件加载到内存映射中,然后在那里随意读取和更新它,并以某个固定或已知的时间间隔将其转储到文件中,对吗?如果是这种情况,那么只需从文件中读取并将数据复制到内存映射指针即可。稍后您可以从 map 中读取数据并将其转换为内存对齐结构并随意使用您的结构。
如果我是你,我可能会创建一些辅助方法,例如
数据读取数据(void *ptr)
和
void WriteData(data *ptrToData, void *ptr)
*ptr
是内存映射地址,*ptrToData
是指向要写入内存的数据结构的指针。真的在这一点上它的内存是否映射并不重要,如果你想从加载到本地内存的文件中读取你也可以这样做。
您可以使用 memcpy 将数据从源复制到目标,以与任何其他 block 数据相同的方式对其进行读/写,并且可以使用指针算法来推进数据中的位置。不要担心“内存映射”,它只是一个指向内存的指针,您可以这样对待它。
此外,由于您将要处理直接内存指针,因此您不需要将每个元素一个一个地写入映射文件,您可以将它们全部写入一批,如
memcpy(mapPointer, data->entries, sizeof(float)*number)
将 data->entries
中的 float*entries 大小复制到映射指针起始地址。显然你可以随心所欲地复制它,无论你想要什么,这只是一个例子。参见 http://www.devx.com/tips/Tip/13291 .
读回数据的方式与您类似,但您希望将内存地址显式复制到已知位置,因此想象一下将您的结构展平。而不是
data:
int
char * -> points to some address
float * -> points to some address
在你的指针指向其他地方的其他内存的地方,像这样复制内存
data:
int
char * -> copy of original ptr
float * -> copy of original ptr
512 values of char array
number of values of float array
所以这样你就可以将内存映射中的数据“重新序列化”到你的本地。请记住,数组只是指向内存的指针。内存在对象中不必是连续的,因为它可以在其他时间分配。您需要确保将指针指向的实际数据复制到您的内存映射中。这样做的一种常见方法是将对象直接写入内存映射,然后在对象后面加上所有展平的数组。读回它首先读取对象,然后将指针增加 sizeof(object)
并读取下一个数组,然后再次将指针增加 arraysize
等。
这是一个例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct data{
int size;
char items[512];
float * dataPoints;
};
void writeToBuffer(data *input, char *buffer){
int sizeOfData = sizeof(data);
int dataPointsSize = sizeof(float) * input->size;
printf("size of data %d\n", sizeOfData);
memcpy(buffer, input, sizeOfData);
printf("pointer to dataPoints of original %x\n", input->dataPoints);
memcpy(buffer + sizeOfData, input->dataPoints, dataPointsSize);
}
void readFromBuffer(data *target, char * buffer){
memcpy(target, buffer, sizeof(data));
printf("pointer to datapoints of copy %x, same as original\n", target->dataPoints);
// give ourselves a new array
target->dataPoints = (float *)malloc(target->size * sizeof(float));
// do a deep copy, since we just copied the same pointer from
// the previous data into our local
memcpy(target->dataPoints, buffer + sizeof(data), target->size * sizeof(float));
printf("pointer to datapoints of copy %x, now it's own copy\n", target->dataPoints);
}
int main(int argc, char* argv[])
{
data test;
for(unsigned int i=0;i<512;i++){
test.items[i] = i;
}
test.size = 10;
// create an array and populate the data
test.dataPoints = new float[test.size];
for(unsigned int i=0;i<test.size;i++){
test.dataPoints[i] = (float)i * (1000.0);
}
// print it out for demosntration
for(unsigned int i=0;i<test.size;i++){
printf("data point value %d: %f\n", i, test.dataPoints[i]);
}
// create a memory buffer. this is no different than the shared memory
char * memBuffer = (char*)malloc(sizeof(data) + 512 + sizeof(float) * test.size + 200);
// create a target we'll load values into
data test2;
// write the original out to the memory buffer
writeToBuffer(&test, memBuffer);
// read from the memory buffer into the target
readFromBuffer(&test2, memBuffer);
// print for demonstration
printf("copy number %d\n", test2.size);
for(int i=0;i<test2.size;i++){
printf("\tcopy value %d: %f\n", i, test2.dataPoints[i]);
}
// memory cleanup
delete memBuffer;
delete [] test.dataPoints;
return 0;
}
在将数据从结构体写入内存时,您可能还想阅读有关数据对齐的内容。检查working with packing structures , C++ struct alignment question , 和 data structure alignment .
如果在读取时不知道数据的大小,则应将数据的大小写入内存映射的开头已知位置,以备后用。
无论如何,要解决我认为在这里使用它是否正确的事实。来自 wikipedia
The primary benefit of memory mapping a file is increasing I/O performance, especially when used on large files. ... The memory mapping process is handled by the virtual memory manager, which is the same subsystem responsible for dealing with the page file. Memory mapped files are loaded into memory one entire page at a time. The page size is selected by the operating system for maximum performance. Since page file management is one of the most critical elements of a virtual memory system, loading page sized sections of a file into physical memory is typically a very highly optimized system function.
您要将整个文件加载到虚拟内存中,然后操作系统可以根据需要为您将文件分页进出内存,从而创建“延迟加载”机制。
总而言之,内存映射是共享的,因此如果它跨进程边界,您需要将它们与命名的互斥锁同步,这样您就不会覆盖进程之间的数据。
关于c++ - 将内存映射数据 block 读入结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12790820/
我在具有 2CPU 和 3.75GB 内存 (https://aws.amazon.com/ec2/instance-types/) 的 c3.large Amazon EC2 ubuntu 机器上运
我想通过用户空间中的mmap-ing并将地址发送到内核空间从用户空间写入VGA内存(视频内存,而不是缓冲区),我将使用pfn remap将这些mmap-ed地址映射到vga内存(我将通过 lspci
在 Mathematica 中,如果你想让一个函数记住它的值,它在语法上是很轻松的。例如,这是标准示例 - 斐波那契: fib[1] = 1 fib[2] = 1 fib[n_]:= fib[n] =
我读到动态内存是在运行时在堆上分配的,而静态内存是在编译时在堆栈上分配的,因为编译器知道在编译时必须分配多少内存。 考虑以下代码: int n; cin>>n; int a[n]; 如果仅在运行期间读
我是 Python 的新手,但我之前还不知道这一点。我在 for 循环中有一个基本程序,它从站点请求数据并将其保存到文本文件但是当我检查我的任务管理器时,我发现内存使用量只增加了?长时间运行时,这对我
我正在设计一组数学函数并在 CPU 和 GPU(使用 CUDA)版本中实现它们。 其中一些函数基于查找表。大多数表占用 4KB,其中一些占用更多。基于查找表的函数接受一个输入,选择查找表的一两个条目,
读入一个文件,内存被动态分配给一个字符串,文件内容将被放置在这里。这是在函数内部完成的,字符串作为 char **str 传递。 使用 gdb 我发现在行 **(str+i) = fgetc(aFil
我需要证实一个理论。我正在学习 JSP/Java。 在查看了一个现有的应用程序(我没有写)之后,我注意到一些我认为导致我们的性能问题的东西。或者至少是其中的一部分。 它是这样工作的: 1)用户打开搜索
n我想使用memoization缓存某些昂贵操作的结果,这样就不会一遍又一遍地计算它们。 两个memoise和 R.cache适合我的需要。但是,我发现缓存在调用之间并不可靠。 这是一个演示我看到的问
我目前正在分析一些 javascript shell 代码。这是该脚本中的一行: function having() { memory = memory; setTimeout("F0
我有一种情况,我想一次查询数据库,然后再将整个数据缓存在内存中。 我得到了内存中 Elasticsearch 的建议,我用谷歌搜索了它是什么,以及如何在自己的 spring boot 应用程序中实现它
我正在研究 Project Euler (http://projecteuler.net/problem=14) 的第 14 题。我正在尝试使用内存功能,以便将给定数字的序列长度保存为部分结果。我正在
所以,我一直在做 Java 内存/注意力游戏作业。我还没有达到我想要的程度,它只完成了一半,但我确实让 GUI 大部分工作了......直到我尝试向我的框架添加单选按钮。我认为问题可能是因为我将 JF
我一直在尝试使用 Flask-Cache 的 memoize 功能来仅返回 statusTS() 的缓存结果,除非在另一个请求中满足特定条件,然后删除缓存。 但它并没有被删除,并且 Jinja 模板仍
我对如何使用 & 运算符来减少内存感到非常困惑。 我可以回答下面的问题吗? clase C{ function B(&$a){ $this->a = &$a; $thi
在编写代码时,我遇到了一个有趣的问题。 我有一个 PersonPOJO,其 name 作为其 String 成员之一及其 getter 和 setter class PersonPOJO { priv
在此代码中 public class Base { int length, breadth, height; Base(int l, int b, int h) { l
Definition Structure padding is the process of aligning data members of the structure in accordance
在 JavaScript Ninja 的 secret 中,作者提出了以下方案,用于在没有闭包的情况下内存函数结果。他们通过利用函数是对象这一事实并在函数上定义一个属性来存储过去调用函数的结果来实现这
我正在尝试找出 map 消耗的 RAM 量。所以,我做了以下事情;- Map cr = crPair.collectAsMap(); // 200+ entries System.out.printl
我是一名优秀的程序员,十分优秀!