64位寻址的地址空间绝对是巨大的.我有一个程序,将有mmap几个内存块,每个大小为100 - 500 MB.我将不可避免地重新映射几次,这可能会导致可用的连续空间出现碎片.
无论空间出现什么碎片,对于可用的地址空间来说肯定会很小.
我的问题是:鉴于这些限制,在正常情况下,我可以期望所有mmap请求成功(即由于碎片而不会失败)吗?他们失败的原因是什么?
我知道堆本身没有整个空间,但我认为它占绝大多数.
Mac OS/Linux.
用打转转mmap了它的乐趣,我有以下代码:
(.. snip ..)
fd = open("/home/me/straight_a.txt", O_RDONLY);
if (fd == -1) {
perror("open");
exit(1);
}
m = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
if (m == MAP_FAILED) {
perror("mmap");
exit(1);
}
printf("m is %p\n", m);
printf("*m = %c\n", *m);
printf("*(m+1) = %c\n", *(m+1));
(.. snip ..)
Run Code Online (Sandbox Code Playgroud)
这按预期工作.但在我做到这一点之前,我试过......
m = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
Run Code Online (Sandbox Code Playgroud)
...和mmap错误地用:
mmap: Permission denied
Run Code Online (Sandbox Code Playgroud)
一般来说,两个标志之间的区别是什么(手册页对这个主题不慷慨)?我遗失了什么样的许可(以及在哪里)?
编辑
喜欢它通常发生..部分想通了.
结果open需要O_RDWR一面旗帜.
那么,我是否正确地假设:
...但我想,我不会把任何东西保存在磁盘上.只是在内存上运行.
由于与此问题无关的一些模糊原因,我需要使用MAP_FIXED来获取靠近libc的文本部分存储在内存中的页面.
在阅读mmap(2)之前(我本来应该做的),如果我用MAP_FIXED调用mmap并且基地址与已经映射的区域重叠,那么我期望得到一个错误.
然而事实并非如此.例如,这是某些进程的/ proc/maps的一部分
7ffff7299000-7ffff744c000 r-xp 00000000 08:05 654098 /lib/x86_64-linux-gnu/libc-2.15.so
Run Code Online (Sandbox Code Playgroud)
其中,在进行以下mmap调用之后......
mmap(0x7ffff731b000,
getpagesize(),
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
0,
0);
Run Code Online (Sandbox Code Playgroud)
... 变成:
7ffff7299000-7ffff731b000 r-xp 00000000 08:05 654098 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff731b000-7ffff731c000 rwxp 00000000 00:00 0
7ffff731c000-7ffff744c000 r-xp 00083000 08:05 654098 /lib/x86_64-linux-gnu/libc-2.15.so
Run Code Online (Sandbox Code Playgroud)
这意味着我用自己的页面覆盖了专用于libc的部分虚拟地址空间.显然不是我想要的......
在mmap(2)手册的MAP_FIXED部分,它清楚地说明:
如果addr和len指定的内存区域与任何现有映射的页面重叠,则将丢弃现有映射的重叠部分.
这解释了我所看到的,但我有几个问题:
目标是从互联网上下载文件,并从中创建一个文件对象,或者像对象这样的文件,而不必触摸硬盘.这只是为了我的知识,想要知道它是否可行或实用,特别是因为我想看看我是否可以避免编写文件删除行.
这就是我通常从网上下载内容并将其映射到内存的方式:
import requests
import mmap
u = requests.get("http://www.pythonchallenge.com/pc/def/channel.zip")
with open("channel.zip", "wb") as f: # I want to eliminate this, as this writes to disk
f.write(u.content)
with open("channel.zip", "r+b") as f: # and his as well, because it reads from disk
mm = mmap.mmap(f.fileno(), 0)
mm.seek(0)
print mm.readline()
mm.close() # question: if I do not include this, does this become a memory leak?
Run Code Online (Sandbox Code Playgroud) 只是问题陈述,我如何使用mmap()在堆中分配内存?这是我唯一的选择,因为malloc()它不是可重入的函数.
我正在开发运行Linux 2.6.37的ARM设备.我试图尽可能快地切换IO引脚.我制作了一个小内核模块和一个用户空间应用程序.我尝试了两件事:
ioremap.mmap() GPIO控制寄存器无需缓存并从用户空间使用它们.两种方法都有效,但第二种方法比第一种方法慢3倍(在示波器上观察).我想我禁用了所有缓存机制.
当然,我想要充分利用这两个领域:从内核空间的速度来看,用户空间的灵活性和易开发性.
有谁知道为什么mmap()可能比这慢ioremap()?
这是我的代码:
static int ti81xx_usmap_mmap(struct file* pFile, struct vm_area_struct* pVma)
{
pVma->vm_flags |= VM_RESERVED;
pVma->vm_page_prot = pgprot_noncached(pVma->vm_page_prot);
if (io_remap_pfn_range(pVma, pVma->vm_start, pVma->vm_pgoff,
pVma->vm_end - pVma->vm_start, pVma->vm_page_prot))
return -EAGAIN;
pVma->vm_ops = &ti81xx_usmap_vm_ops;
return 0;
}
static void ti81xx_usmap_test_gpio(void)
{
u32* pGpIoRegisters = ioremap_nocache(TI81XX_GPIO0_BASE, 0x400);
const u32 pin = 1 << 24;
int i;
/* I should use IO read/write functions instead of pointer deferencing,
* but portability isn't …Run Code Online (Sandbox Code Playgroud) 我想通过在Linux中使用内存映射I/O来尝试将文件的内容复制到另一个文件mmap().目的是自己检查一下这是否比使用更好fread(),fwrite()以及它如何处理大文件(例如,像几个GiB,因为文件被读取整个我想知道如果我需要有这么多的内存量).
这是我正在使用的代码:
// Open original file descriptor:
int orig_fd = open(argv[1], O_RDONLY);
// Check if it was really opened:
if (orig_fd == -1) {
fprintf(stderr, "ERROR: File %s couldn't be opened:\n", argv[1]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
exit(EX_NOINPUT);
}
// Idem for the destination file:
int dest_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
// Check if it was really opened:
if (dest_fd == -1) {
fprintf(stderr, "ERROR: File %s couldn't be …Run Code Online (Sandbox Code Playgroud) 在mmap()手册页中:
它的原型是:
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
Run Code Online (Sandbox Code Playgroud)
和描述:
The mmap() function asks to map 'length' bytes starting at offset 'offset'
from the file (or other object) specified by the file descriptor fd into
memory, preferably at address 'start'.
Run Code Online (Sandbox Code Playgroud)
最后,对于最后一个论点:
'offset' should be a multiple of the page size as returned by getpagesize(2).
Run Code Online (Sandbox Code Playgroud)
根据我的实践,offset必须是页面大小的倍数,例如,我的Linux上有4096,否则,mmap()会返回Invalid argument,offset是文件偏移量,为什么它必须是虚拟内存系统页面大小的倍数?
谢谢,
考虑一个使用大量页面大小的内存区域(比如64 kB左右)的程序,每个区域都是相当短暂的.(在我的特定情况下,这些是绿色线程的备用堆栈.)
如何最好地分配这些区域,以便一旦该区域不再使用,它们的页面可以返回到内核?天真的解决方案显然只是mmap单独的每个区域,munmap一旦我完成它们就会再次出现.不过,我觉得这是一个坏主意,因为它们有很多.我怀疑VMM可能会在一段时间后开始严重缩放; 但即使没有,我仍然对理论案例感兴趣.
如果我只是mmap自己一个巨大的匿名映射,我可以根据需要分配区域,有没有办法通过映射"打孔"我已完成的区域?有点像madvise(MADV_DONTNEED),但不同之处在于应该将页面视为已删除,以便内核实际上不需要将其内容保留在任何位置,但只要再次出现故障就可以重用已归零的页面.
我正在使用Linux,在这种情况下,我并不打算使用特定于Linux的调用.
有谁知道为什么mmap()返回MAP_FAILED而不是NULL?在大多数系统上,似乎MAP_FAILED是(void*) - 1.为什么mmap()不使用NULL代替?我知道地址0x0在技术上是一个有效的内存页面,而(void*) - 1永远不会是一个有效的页面.但我的猜测是mmap()实际上永远不会实际返回页面0x0.例如,在Windows上,VirtualAlloc()在出错时返回NULL.
假设mmap()永远不会返回0x0是否安全?大概是对mmap()的成功调用应该将可用内存返回给调用者.地址0x0永远不可用,因此成功时永远不应返回.这种情况会让使用0x0作为失败的哨兵似乎是明智的,这就是为什么我首先对MAP_FAILED的存在感到困惑.