有以下一段代码:
#include <stdlib.h>
#pragma pack (1)
class MyInt{
long value;
public:
MyInt(long v){value = v;}
};
typedef MyInt* LpMyInt;
int main(){
int count = 1024*1024;
LpMyInt* pIntArr = new LpMyInt[count];
for (int i=0; i<count; i++)
pIntArr[i] = new MyInt(i);
system("pause");
return 0;
}
不解的是为什么程序需要占有29536K的内存呢?(compiler: gcc3.3.1)
我的计算以为大概是sizeof(LpMyInt)*count+sizeof(MyInt)*count=4*1M+4*1M=8M
请各位高手解答.
程序占用的内存不等于你分配的内存.
程序要运行你的代码要地方来放吧,堆栈也需要空间吧....
这我也知道, 可是这些空间不至于要20M以上吧.
你的内存是如何得到的?
程序运行要先把程序本身放到内存中才行!
呵呵, 我指的是任务管理器中的读数. 不知道准不准.
这这... ...最近啥问题都有了,我还真是不太清楚啊.
还有一个奇怪的现象, 代码如下:
#pragma pack (1)
#include <stdlib.h>
class MyInt{
long value;
long value2; //增加一个data member, 内存占有不变
public:
MyInt(long v){value = v;}
};
typedef MyInt* LpMyInt;
int main(){
int count = 1024*1024;
LpMyInt* pIntArr = new LpMyInt[count];
for (int i=0; i<count; i++)
pIntArr[i] = new MyInt(i);
system("pause");
return 0;
}
#pragma pack (1)
#include <stdlib.h>
class MyInt{
long value;
long value2;
long value3;
long value4; //如果一直添加到第4个data member, 内存不会改变
long value5; //但是如果增加到第5个, 内存一下子就从29536K到了45956k
public:
MyInt(long v){value = v;}
};
typedef MyInt* LpMyInt;
int main(){
int count = 1024*1024;
LpMyInt* pIntArr = new LpMyInt[count];
for (int i=0; i<count; i++)
pIntArr[i] = new MyInt(i);
system("pause");
return 0;
}
任务管理器中的性能监视器得到的内容可能并不精确,如果用虚拟内存的话,它如何计算?
另外你用到的库函数也需要空间,还有编译器帮你增加的一些内容。
嗯, 的确不精确, 但是我觉得奇怪的是差距为什么是几倍如此之大. 类似的代码, 下面的代码就只需要4892K内存.
#pragma pack (1)
#include <stdlib.h>
class MyInt{
long value;
public:
MyInt(){};
MyInt(long v){value = v;}
};
typedef MyInt* LpMyInt;
int main(){
int count = 1024*1024;
LpMyInt IntArr = new MyInt[count];
for (int i=0; i<count; i++)
IntArr[i] = i;
system("pause");
return 0;
}
对了~
这样为什么就是这个数字呢??
这就比较符合估算了.
我的机子上面是2456K~~
一个程序运行需要很多资源!
程序所在进程的用户空间不够了,就增加一些空间啥。!
你一开始的程序在我的机子上面和你刚改的内存都一样~~
我也在任务管理器上面读数~~~
搞不懂了~~~
哦!
不好意思~~
搞错了~~
对于动态分配的内存,实际分配的内存会比你申请的多。
多出来的部分:一部分是给内存管理用;一部分是为了使申请的内存大小凑成某个数的整数倍,或者是为了凑到一个最小分配大小。
你可以连续new两个int,把两个指针减一下,就可以知道new一个int实际申请了多少bytes。
我的估计: c++在new内存时, 做了限制, 每次分配new的内存大小必须为16Byte的倍数, 如16, 32,48,...等等. 所以我每次new 4Byte (1个long)实际上与new 16Byte (4个long)没有区别.
后来, 我改了一下代码, 改用list来保存对象. 按理, list的开销应该要比较大, 因为它除了记住内存指针,还有又nextnode和prevnode的开销, 所以总的内存应该比第一个例子(29536K)要多些才对. 可是, 结果不是这样的, 它只需要17248k, list的代码如下:
#pragma pack (4)
#include <stdlib.h>
#include <list>
class MyInt{
long value;
public:
MyInt(){};
MyInt(long v){value = v;}
};
typedef MyInt* LpMyInt;
int main(){
int count = 1024*1024;
std::list<MyInt> intList;
for (int i=0; i<count; i++)
intList.push_back(MyInt(i));
system("pause");
return 0;
}
于是, 我去看了list的源代码, 发现list每次new的时候, 并不是只new一个对象的内存的, 而是new了一片内存, 然后push_back时用的时placement new.所以它就比每次new 4Byte花的内存少.
不知道我的想法对不对, 我查了些资料, 都没有找到答案.
实际分配的内存会比你申请的多。
编译器要考虑内存对齐的问题,所以要多申请一些内存。
不知道可不可以做以下结论:
避免大量的new小内存对象.
其中, 大量指100000次以上,
小内存对象指sizeof(smallobject)<16byte.
如果一定要创建极大量的小内存对象, 则应该预先申请一块连续的大内存块, 然后用placement new方法new小内存对象.
这个问题可就复杂了,跟你的编译优化级别O也有关系,跟操作系统的内存分配策略也有关系。stl是使用placement new机制使用内存的,碎片比较少,遇有这种情况时,你可以自己重载new方法试试,其实也就是placement new的方法,占用肯定会减少。
memory pool
一是你的C runtime使用了memory pool,二是操作系统的ALLOC也有一定开销
int count=1024*1024;????????
内存泄漏了吧
这个其实不是问题,作为一个应用程序来讲,它理论上可以占用4G内存空间。虽然实际上往往小于这个数值,因为操作系统一般会占有1G,同时你的程序也很难用到这个大的地址范围,而且我们的内存也有限。但是为什么任务管理器所显示的内存在有量却远远大于我们本身所计算或设想的大小呢?这要从操作系统对内存的管理上说起了。
每个应用程序所使用的地址,并不是真正的物理内存的地址,这个我们首先要意识到。应用程序使用的地址我们称之为虚拟地址或线性地址,需由操作系统进行转换之后映射到对应的物理地址上。操作系统在给应用程序分配内存的时候,使用的就是虚拟地址,虽然应用程序可能仅需要1k的空间,但是操作系统并不一定就分配1k空间,往往要大于这个请求值,一般是4k,8k。如果连续申请较小的数据的话,那么就会出现几倍于请求大小的虚拟地址空间了。当然,很多编译器在这方面进行了优化,请求的数据远远小于4k的时候,即使多次调用new等操作,只要总大小不超过4k,那么它就不请求操作系统分配内存,而且他组织数据的方式会将块分得更小,比如8字节,16字节等,这样更节省空间。其实主要的目的是节省物理内存空间。因此虚拟地址的4k,对应到物理地址上的也是4k,这本身是硬件限制的。但是到了申请大块数据的时候,情况有所有不同了。这个时候编译器帮不上忙,只能有操作系统自身解决。为了提高内存分配速度,一般要保证所分配内存的连续性,那么操作系统会对内存地址空间进行保留,不允许其他模块,比如dll再在这个空间内分配内存了。这个保留区域往往大于所申请的区域,具体比例会根据操作系统的不同而不同。然而这部分保留区域也算是应用程序的一部分。
另外,一个程序在系统中运行,往往不是孤立的,一般还要装在运行时库或其他别的模块,虽然这些模块在物理内存方面来看,他们是共享的,但是在虚拟地址空间上看,他们确实独立的,因此他们所占用的内存空间也要算在应用程序身上。
由此根据上面的叙述,可见任务管理器表明应用程序所占用的空间,并不是程序真正所用到的物理内存空间,而是其虚拟地址空间。这个值往往会比实际情况大很多。因此楼主的程序全属正常,不需要为这方面而担忧。
up
问题应该是出在这里new LpMyInt[count]
new操作符应该用在小内存的分配上,大内存应该用Malloc的操作符
在我的机器上Win32控制台的程序返回值不正确了。
同意 jiajun2001(嘉俊) ( ) 信誉:100 的说法