InMySin 发表于 2012-07-22 11:33

请教一个C/C++ 内存问题,动态new,奇怪现象

本帖最后由 InMySin 于 2012-07-22 11:45 编辑

论坛之前有类似帖子,但是回复我还是搞不懂,于是自己动手写了写:
好啦,问题来了,我这个程序在无限循环地申请内存,每次申请应该为 10000000*4 byte( 为了内存管理而增加的一点开销暂时不管),
g++ -Wall crapp.cpp -o crapp编译通过,有点警告,主要是为了输出地址,使用%u 应该是正确的,%d会出现负数?

然后./crapp 运行

我开始以为这个程序由于不断申请内存,导致系统内存不足,然后想观察下发生什么情况:),我每次运行前都free -m 一下:
                   total         used       free   shared    buffers   cached
Mem:          1759       1437      321          0      126      417
-/+ buffers/cache:       893      866
Swap:         1035          0       1035

内存可用也就是321MB左右,这样我申请的应该很快把这个321内存用光,但是实际是:运行程序后,我不断free -m 可用内存却几乎没有大的变化,程序最终
new失败而core dump;

程序输出:
./crapp
Stack is 3213834968---》 大概可以看到main里面的局部变量 分配位置,用bc(我用bc算错了,改成octave)算一算,真的在3G 左右,不是我在操作系统里面认为那样,每个进程4G逻辑空间,stack栈应该在顶层,也就是4G左右的地方,这个与我之前看法完全不同;

New 4m 0
The p=3038351368
New 4m 1
The p=2998349832
New 4m 2
The p=2958348296
New 4m 3
The p=2918346760   -》》》在heap堆上的内存,上网找找好像说超过128K,堆是往下增长,而不是往上增长的?? 之前看linux program的书都是堆在地址低地方不断向上增长,但是这又个我之前看法不同!


最重要是,这些都能分配成功了,一次大概40M,free -m 中used free几乎没有变化,难道我不写内核就只是帮我记录一下分配空间,但是并不是实际分配物理内存??


最后,这个程序不能搞崩溃OS,都是这样被杀掉了:
New 4m 77
terminate called after throwing an instance of 'std::bad_alloc'
what():std::bad_alloc
Aborted (core dumped)

但是同学们跑时候首先sync好,关闭一些重要程序拉,,求知道#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

int main( int argc , char ** argv )
{
    int * p;
    int cnt;

    cnt = 0;

    printf("Stack is %u\n" , &p );
    while( true )
    {
        sleep( 1 );

        fprintf( stderr , "New 4m %d\n" , cnt++);
        p = new int;

        p = 124;

        fprintf( stderr , "The p=%u\n" , p );


    }

    return 0;
}

InMySin 发表于 2012-07-22 11:36

还有系统一些信息:
Linux df 2.6.35.14-106.fc14.i686 #1 SMP Wed Nov 23 13:57:33 UTC 2011 i686 i686 i386 GNU/Linux

ulimit -a
core file size          (blocks, -c) 0
data seg size         (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals               (-i) 13974
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues   (bytes, -q) 819200
real-time priority            (-r) 0
stack size            (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes            (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

crazyhadoop 发表于 2012-07-22 18:30

系统有过载自我保护功能,不会让你这么无限的malloc的,超过极限就失败了,

MMMIX 发表于 2012-07-23 13:29

InMySin 发表于 2012-07-22 11:33 static/image/common/back.gif
最重要是,这些都能分配成功了,一次大概40M,free -m 中used free几乎没有变化,难道我不写内核就只是帮我记录一下分配空间,但是并不是实际分配物理内存??

你分配到的始终都是虚拟内存,物理内存是 OS 在管理。


最后,这个程序不能搞崩溃OS,都是这样被杀掉了:
New 4m 77

这样就能被搞崩溃的 OS 是不是太脆弱了点?另外,算算 40 * 77 大概是多少。

g__gle 发表于 2012-07-23 15:07

现代OS大部分设计成内核与用户位于同一地址空间。也是就是说,4G的虚拟地址里,内核要占用一部分。

分配线性地址而不分配物理内存,完全合理,甚至大部分情况下是常态。这是两种不同的资源,前者是per-process的,后者是整个系统的,OS不一定会成对分配,这就是所谓的page on demand。分配线性地址时,OS只是做个标记,并没为其安排物理内存。真正访问这个地址时,硬件发现这个地址下没有对应物理内存,产生page fault,OS处理这个错误时,发现承诺过给这个地址一块内存,继而系统中为其分配资源。用户态访问这个地址的整个过程中,完全看不到内核这一系列动作。

InMySin 发表于 2012-07-23 16:38

回复 4# MMMIX


    恩恩,昨天看了相关资料,大概明白,malloc/new 得到还是地址空间的内存,实际上的物理内存是内核做了映射,而这些物理内存可能是按需分配的,我不访问它就不用分配。。。

40*77 = 3080; 也跟网上说的 32位, 1G 内核空间,3G的用户空间,我把3G的用户空间的地址都用光了,所以再在3G的地址内malloc就肯定失败了。。

InMySin 发表于 2012-07-23 16:44

回复 5# g__gle


    看了linux地址空间/内存布局等,明白你在说什么了,但是有个问题是,我通过 malloc 申请的一个 固定大小的 内存块(例如 40M),这些地址是连续的,但是映射都物理内存上就可能不是连续了,这40M的地址可能是OS东凑西凑拼起来了,还是一定有个40M大小的块?? 我认为应该是用页拼起来的,但是页可能不连续。。

xiyoulaoyuanjia 发表于 2012-07-25 22:54

我觉得是用页拼凑起来的!内存管理程序通过映射机制把用户程序的逻辑地址映射到物理地址,对于你用malloc申请的连续的堆,你的访问每次都需要mmu 将逻辑地址转换成物理地址,如果发现程序中要用的虚地址没有对应的物理内存时,就发出了请页要求(当然页要求是连续的),程序要两种机制保证可以 满足1.内存的分配与回收!2.交换地址 保证页连续!

wonderall01 发表于 2012-07-31 14:28

我在centos上试了下,先用掉内存的空间,然后采用交换空间的,但让我迷惑的是,不管我申请多少空间,内存空间会马上用完。有知道是怎么回事的吗?

lxxgreat 发表于 2012-10-15 09:07

这个与具体的系统有关,我在ubuntu下测试与楼主结果一样,但在windows下测试,则显示很快耗尽物理内存了。。。
页: [1]
查看完整版本: 请教一个C/C++ 内存问题,动态new,奇怪现象