标签: virtual-memory

malloc在不同的机器上表现不同

在运行一个试图在不同机器上超过RSS的程序时,我看到完全不同的行为.代码类似于:

...
  char** s = (char**)malloc(10000*sizeof(char*));

  for (i = 0; i < 10000; i++){
    s[i] = (char*)malloc(1000*1000*sizeof(char));
    if (s[i] == NULL) {
      printf("cannot allocate memory for s[%d]",i);
      exit(1);
    }
  }

  int j = 0;
  while(1){
    for (i = 0; i < 10000; i++){
      for (j = 0; j < 1000*1000; j++) {
        s[i][j] = 1;
      }
      if ((i % 100) == 0) printf("i = %d\n", i);
    }
  }
  for (i = 0; i < 10000; i++)
    free(s[i]);
  free(s);
...
Run Code Online (Sandbox Code Playgroud)

上面的代码尝试使用malloc分配大约10GB的内存.我试过这个代码的前两台机器在linux内核2.6上运行,最后一台运行linux内核2.4.以下是我在这些机器上看到的行为: …

c linux malloc paging virtual-memory

5
推荐指数
1
解决办法
720
查看次数

fork 和内核中映射的用户空间内存的交互

考虑使用get_user_pages(或get_page)映射来自调用进程的页面的 Linux 驱动程序。然后将页面的物理地址传递给硬件设备。进程和设备都可以读取和写入页面,直到双方决定结束通信。特别地,在调用get_user_pages返回的系统调用之后,通信可以继续使用页面。系统调用实际上是在进程和硬件设备之间建立一个共享内存区域

我担心如果进程调用会发生什么fork(它可能来自另一个线程,并且可能在调用的系统调用get_user_pages正在进行中或稍后发生)。特别是,如果父级在fork后写入共享内存区域,我对底层物理地址了解多少(可能是因为copy-on-write而改变)?我想明白:

  1. 内核需要做什么来防御潜在的行为不端的进程(我不想创建安全漏洞!);
  2. 进程需要遵守哪些限制,以便我们的驱动程序的功能正常工作(即物理内存保持映射到父进程中的相同地址)。

    • 理想情况下,我希望子进程根本不使用我们的驱动程序(它可能exec几乎立即调用)来工作的常见情况。
    • 理想情况下,父进程在分配内存时不应采取任何特殊步骤,因为我们已有将堆栈分配的缓冲区传递给驱动程序的现有代码。
    • 我知道madvisewith MADV_DONTFORK,并且可以让内存从子进程的空间中消失,但它不适用于堆栈分配的缓冲区。
    • “当您与我们的驱动程序有活动连接时不要使用叉”会很烦人,但如果满足第 1 点,则可以作为最后的手段。

我愿意被指出文档或源代码。我特别查看了Linux Device Drivers,但没有发现这个问题得到解决。即使只是应用于内核源代码的相关部分的 RTFS 也有点让人不知所措。

内核版本不是完全固定的,而是最近的版本(比如 ??2.6.26)。如果重要的话,我们只针对 Arm 平台(目前是单处理器,但多核即将到来)。

fork shared-memory virtual-memory linux-kernel

5
推荐指数
1
解决办法
2619
查看次数

具有16GB虚拟内存且不断增长的Java程序:这是一个问题吗?

在Mac OSX 5.8上,我有一个Java程序,它运行在100%CPU很长一段时间 - 几天或更长时间(这是一个模型检查器分析并发程序,因此或多或少的预期).然而,它的虚拟内存大小,如OSX的活动监视器所示,在一天左右后变得非常庞大:现在它已经是16GB并且在不断增长.物理内存使用率大致稳定在1.1GB左右.

我想知道:16GB(并且还在增长)是一个问题的迹象,可能会减慢我的程序?

I start the program with "java -Xmx1024m -ea"

java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07-334-9M3326)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02-334, mixed mode)
Run Code Online (Sandbox Code Playgroud)

感谢大家的建议.我将尝试在一些答案中给出的分析建议并返回(可能需要一段时间,因为多天的运行时间).

在回答下面的一些要点时,模型检查器几乎不执行任何I/O(仅打印语句,具体取决于调试设置).在我使用的模式中它没有GUI.我不是模型检查器的主要作者(虽然我已经在它的一些内部工作),但我不相信它使用JNI.[<---编辑:这是错的,详情如下]它没有做任何内存映射.另外,我不是要求Oracle/Sun的JVM创建大量线程(请参阅下面的解释).

额外的虚拟内存没有导致模型检查器死亡,但是基于打印输出的频率,随着虚拟内存使用量的增加,它逐渐运行得越来越慢.(也许这只是因为垃圾收集越来越多.)我计划在周一在Windows机器上试用它,看看是否会发生同样的问题.

一点额外的解释:我正在运行的模型检查器(JPF)本身就是一个几乎完整的JVM(完全用Java编写),它运行在Oracle/Sun的JVM下.当然,作为虚拟机,JPF非常专业化以支持模型检查.

这有点违反直觉,但这意味着即使我模型检查的程序设计为多线程,就Sun的JVM而言,只有一个线程:运行JPF的线程.JPF模拟我的程序需要的线程作为其模型检查过程的一部分.


我相信斯蒂芬C已经指出了这个问题; Roland Illig给了我验证它的工具.我对JNI的使用是错误的.JPF本身不使用JNI,但它允许插件和JNI被其中一个配置的插件使用.幸运的是,我可以使用纯Java的等效插件.其中一个的初步使用显示在过去几个小时内虚拟内存没有增长.感谢大家的帮助.

java performance virtual-memory

5
推荐指数
1
解决办法
5993
查看次数

在大型阵列上使用 VirtualAlloc 保留与提交 + 保留内存的优势

我正在编写一个 C++ 程序,它基本上适用于非常大的数组。在 Windows 上,我使用 VirtualAlloc 为我的数组分配内存。现在我完全理解了使用 VirutalAlloc 保留和提交内存的区别;但是,我想知道将内存逐页提交到保留区域是否有任何好处。特别是,MSDN ( http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx ) 包含对 MEM_COMMIT 选项的以下解释:

除非/直到实际访问虚拟地址,否则不会分配实际的物理页面。

我的实验证实了这一点:我可以保留和提交几 GB 的内存,而不会增加进程的内存使用量(如任务管理器中所示);只有当我实际访问内存时才会分配实际内存。

现在我看到很多例子认为应该保留大部分地址空间,然后逐页提交内存(或在一些更大的块中,取决于应用程序的逻辑)。然而,正如上面所解释的,在访问内存之前似乎并没有提交内存。因此,我想知道逐页提交内存是否有任何真正的好处。事实上,由于许多实际提交内存的系统调用,逐页提交内存实际上可能会减慢我的程序速度。如果我一次提交整个区域,我只需为一次系统调用付费,但内核似乎足够聪明,实际上只分配了我实际使用的内存。

如果有人能向我解释哪种策略更好,我将不胜感激。

winapi memory-management virtualalloc virtual-memory

5
推荐指数
1
解决办法
2426
查看次数

多个堆栈和堆放在虚拟内存中的哪个位置?

我正在写一个内核和需求(并希望)把多个栈和堆到虚拟内存,但我无法弄清楚如何有效地把它们.普通程序如何做到这一点?

堆栈和堆是如何(或在哪里)放入32位系统提供的有限虚拟内存中,以便它们具有尽可能多的增长空间?

例如,当一个简单的程序加载到内存中时,其地址空间的布局可能如下所示:

[  Code  Data  BSS  Heap->  ...  <-Stack  ]
Run Code Online (Sandbox Code Playgroud)

在这种情况下,堆能够增长大如虚拟内存允许(如到堆栈),我相信这是堆是如何工作的大多数程序.没有预定义的上限.

许多程序都将共享库放在虚拟地址空间中的某个位置.然后有多线程程序,有多个堆栈,每个线程一个..NET程序有多个堆,所有这些都必须能够以这种或那种方式增长.

我只是没有看到如何在没有对所有堆和堆栈的大小预先设定的限制的情况下合理有效地完成这项工作.

heap stack operating-system virtual-memory

5
推荐指数
1
解决办法
584
查看次数

ELF部分的错误对齐值导致程序加载错误

我目前正在使用自定义链接描述文件构建玩具操作系统来创建二进制文件:

ENTRY(entry_point)

/* base virtual address of the kernel */

VIRT_BASE = 0xFFFFFFFF80000000;

SECTIONS
{
    . = 0x100000;

    /*
     * Place multiboot header at 0x10000 as it is where Grub will be looking
     * for it.
     * Immediately followed by the boot code
     */

    .boot :
    {
        *(.mbhdr)
        _load_start = .;
        *(.boot)

        . = ALIGN(4096);

        /* reserve space for paging data structures */

        pml4 = .;
        . += 0x1000;
        pdpt = .;
        . += 0x1000;
        pagedir = .;
        . += …
Run Code Online (Sandbox Code Playgroud)

c++ operating-system elf dynamic-linking virtual-memory

5
推荐指数
0
解决办法
727
查看次数

在linux中计算页面错误导致混乱的结果

我正在编写程序来计算linux系统中页面错误的时间.更确切地说,时间内核执行该功能__do_page_fault.
并不知我写了两个全局变量,命名pfcount_at_begpfcount_at_end,当功能,增加一次__do_page_fault在函数的不同地点被执行.

为了说明,修改后的功能如下:

unsigned long pfcount_at_beg = 0;
unsigned long pfcount_at_end = 0;
static void __kprobes
__do_page_fault(...)
{
    struct vm_area_sruct *vma;
    ...    // VARIABLES DEFINITION 
    unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;   
    pfcount_at_beg++;        // I add THIS
    ...
    ... 
    // ORIGINAL CODE OF THE FUNCTION
    ...
    pfcount_at_end++;        // I add THIS
}
Run Code Online (Sandbox Code Playgroud)

我预计pfcount_at_end的值小于pfcount_at_beg的值.

因为,我认为,每次内核执行代码指令时pfcount_at_end++,它都必须执行pfcount_at_beg++(每个函数都从代码的最开始处开始).
另一方面,由于return这两行代码之间存在许多条件.

然而,结果反过来说.值pfcount_at_end大于pfcount_at_beg.的值.
我用来printk通过自定义打印这些内核变量syscall.我写了用户级程序来调用system …

linux kernel virtual-memory

5
推荐指数
1
解决办法
158
查看次数

在VirtualAlloc中对齐内存

作为Win64上某些代码的优化,我保留了4GB的地址空间,然后在该地址空间内提交了一定数量的MB(例如512MB)(最终通过数组绑定检查删除提供了巨大的性能提升,但这一切都在点).我的代码基本上是这样的:

LPVOID address = VirtualAlloc(null, FOUR_GB, MEM_RESERVE, PAGE_NOACCESS);
arrayAddress = VirtualAlloc(address, length, MEM_COMMIT, PAGE_READWRITE);
Run Code Online (Sandbox Code Playgroud)

我团队中的某个人最近阅读了一篇关于大页面需要较少TLB查找并且在某些情况下性能显着提高的论文,这似乎是尝试这一点的主要候选者.

但是,我正在阅读的内容让我觉得这可能不起作用.MSDN说"大小和对齐必须是大页面最小值的倍数".我可以很容易地确保长度是大页面最小值的倍数,但是我如何才能进行对齐?如果我可以将MEM_LARGE_PAGES标志传递给预留,我认为这将正确对齐它.但我已经读过你不能用MEM_RESERVE | MEM_LARGE_PAGES调用VirtualAlloc.

所以我的想法是我可以做我现在正在做的事情,但是在预订期间使用FOUR_GB + GetLargePageMinimum()进行VirtualAlloc,然后在提交时将地址与GetLargePageMinimum()对齐,但这对我来说感觉不对.

有谁知道正确的方法呢?

winapi virtual-memory

5
推荐指数
1
解决办法
551
查看次数

禁用x86 32位中的分页

我试图直接写入物理内存位置,所以我使用汇编函数首先禁用分页,写入值,然后重新启用分页,但由于某种原因,在尝试编写时仍会触发页面错误值.

据我所知,在x86-32bit中,通过在cr0中翻转位32来设置打开和关闭分页,所以这是我的汇编函数:

mov 4(%esp), %ecx //address
mov 8(%esp), %edx //value

mov %cr0, %eax
and $0x7fffffff, %eax
mov %eax, %cr0

mov %edx, (%ecx) //this line still triggers a page fault somehow

or $0x80000000, %eax
mov %eax, %cr0

ret
Run Code Online (Sandbox Code Playgroud)

这是实现我想做的正确方法吗?如果是这样,为什么还会在cr0中的位翻转时触发页面错误?

paging x86 assembly virtual-memory page-fault

5
推荐指数
1
解决办法
1108
查看次数

地址随机化:c中静态变量的打印地址

我正在阅读操作系统教科书,有一个例子验证系统是否支持虚拟地址,并说下面的程序每次都应该打印相同的结果.我看到我的macbook pro有些不同.

#include <stdio.h>

int var = 0;
int main(void)
{
  var += 1;
  printf("Address: %x, value: %d\n", &var, var);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

当它运行时,我看到地址在某些字节中发生了变化(但不是所有字节):

./main
Address: e8c6018, value: 1
./main
Address: 9032018, value: 1
./main
Address: 1bc7018, value: 1
Run Code Online (Sandbox Code Playgroud)

当我在GDB中运行时,我总是看到1018:

(gdb) r
Starting program: /Users/xilan/temp/main
Address: 1018, value: 1
[Inferior 1 (process 19631) exited normally]
(gdb) r
Starting program: /Users/xilan/temp/main
Address: 1018, value: 1
[Inferior 1 (process 19636) exited normally]
(gdb) r
Starting program: /Users/xilan/temp/main
Address: 1018, value: 1
[Inferior …
Run Code Online (Sandbox Code Playgroud)

c static virtual-memory

5
推荐指数
1
解决办法
100
查看次数