【各位帮个忙】程序运行时堆区和栈区是如何分配的【先道谢了!】

mabo321 2009-01-24 12:05:58
程序运行时堆区和栈区是如何分配的??
是堆区分配的大?还是栈区分配的大?

还有就是,在定义类的成员对象时,是弄成指针好?还是对象好?

//看别人写的 怎么都是指针啊,这样势必要在堆区建立对象,而且还要管理对象的释放。。。
//有的地方 我感觉直接定义对象比较好…… 各位有何高见?? 先道声谢……



(只能发100的贴,如有满意结果 加100 后结贴)
...全文
382 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
hangyu628 2009-01-25
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 xiaoyisnail 的回复:]
c++更建议用引用而不是指针,引用或指针相对直接用对象减少了很多内存复制上的开销,不过用指针带了内存管理上的问题,所以c++中更多的应该学会使用引用
[/Quote]

支持1楼的,关于你说的指针问题,还有一点还是看个人习惯,像我的话,主要以引用与普通变量.
刚从MFC转变,开始系统重新学习C++...了
hangyu628 2009-01-25
  • 打赏
  • 举报
回复
关于堆与栈的,今天刚看的,并总结的...
栈(stack):是自动分配变量,以及函数调用所使用的一些空间(所谓的局部变量),地址由高向低减少;
堆(heap):由malloc,new等分配的空间的地址,地址由低向高增长。
自己所编写的代码:
#include <iostream>
using namespace std;
void main()
{
int a;
int b;
int *p1;
int *p2;
cout<<&a<<endl<<&b<<endl<<&p1<<endl<<&p2<<endl<<endl;
//结果显示:0012FF7C,0012FF78,0012FF74,0012FF70;可见,栈中的地址是减少的
int *p3=new int[1];
int *p4=new int[1];
cout<<p3<<endl<<p4<<endl;
//结果显示:003907A8,003907E0;可见,堆中地址是增加的
}

有一点应该注意:频繁使用heap 会产生内存碎片,而按照堆栈的先入后出原则,即先申请的后释放原则可以有效地避免在堆中产生碎片。
栈区中的局部数据占有的空间在函数结束后会自动释放,而堆中的要由程序员手动释放。此外,栈中分配的空间一般于编译时就确定大小(windows是2M,这个我还不怎么理解),而若要在运行时分配空间,就得用堆。栈一般空间有限,若申请空间过大(比如int a[400000])会出现溢出(overflow).

堆和栈中的存储内容
Stack栈: 在函数调用时,第一个进栈的是主函数中 函数调用语句的下一条可执行语句的地址,然后是函数的各个参数,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
heap堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。


程序的内存分配
一个由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。与数据结构栈类似
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事。
3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

引用的一个例子:
//main.cpp
#include <iostream>
using namespace std;
int a = 0; //全局初始化区
char *p1; //全局未初始化区
void main()
{
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456\0在常量区,p3在栈上。
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在堆区。注意:P2本身是在栈中的
strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的,"123456"优化成一个地方。
}

dongpy 2009-01-25
  • 打赏
  • 举报
回复
程序运行时堆区和栈区是如何分配的?? ================================================================================================
堆是紧接着数据段分配的,用户通过malloc/free与C库接口,而C库中的堆管理单元再通过系统调用brk/sbrk与操作系统接口.
栈一般在用户空间的最高地址处,程序运行时自动向下扩展.


是堆区分配的大?还是栈区分配的大?
==========================================
可分配空间肯定是堆大.
栈从属于线程,每个线程的栈大小有上限值,访问超出时,会出现"栈溢出"错误.
堆的大小与用户地址空间和系统可分配物理页面有关,因此可以分配很大的空间.

堆和栈的使用是根据实际需求定的,堆上能分配很大空间,堆被所有线程共享,堆内存的分配和释放需要显式调用函数,栈
则不需要,是编译器自动完成的.
一般来说,一些体积不大的临时对象,局部对象,在栈上分配.而一些体积较大的或者全局的对象,在堆上分配.
有时候定义基类的指针,是使用类的多态性的原因.
larrypeng 2009-01-25
  • 打赏
  • 举报
回复
Heap和stack的区别:
(1)heap
heap是在装入程序的时候创建的。
OS装入程序的时候,会创建程序段空间,并且注册CPU的全局寄存器,将这段空间映射为虚拟地址。OS还会创建heap段,并且映射heap段的虚拟地址空间,以上地址映射通过注册GDT和LDT来完成。并且通过维护一个列表,这两个段的地址控件可以扩展。通常来说,heap段认为是数据段。

(2)stack
这个是个先进后出的数据结构,通过pushl和popl来实现。不仅可以储存变量,还可以储存函数地址,在多任务系统中实现任务切换。通常来说,1000个字节足够大了。因为通常不会通过函数传递太多的变量,这样的程序让自己也看不懂。有些OS把堆栈段放在程序段的后面,不分配一个独立的地址空间,因为实在没必要。比如FreeBSD. Windows 是按页分配的Stack段。

所以,windows下程序段,heap段,stack段具有不同的地址控件,但实际上,他们是物理地址毗邻的内存单元。heap段在常见的时候,维护了一个链表结构,用于储存8、16,32、64、128,256,512、1024等大小的地址单元,所以,malloc运行时,是把内容放入预先创建的内存单元内,比如,你创建的大小是257,这个内容被放入大小为512的内存单元内。

所以new 或 malloc 占用的内存单元,必须要释放掉。
genius_tong 2009-01-25
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 waizqfor 的回复:]

Every process has 4 segments, data, text, stack, and heap.

Data segment is for global, static data member, as well as static variable in a function. So, in your example, a, pl, and d are in data segment.

Text segment is for code, all the compile generated (corresponding to your source code) code stored in this are.

Stack is for local variables as well as the activation record of fu…
[/Quote]
学习了,upup
华亭真人 2009-01-25
  • 打赏
  • 举报
回复
说的简单点吧
int a=10;
这会分配在栈里,在程序结束时会自动释放

CMyClass c=new CMyClass();
这是分配在堆里的,一定要手动释放
delete c;
hityct1 2009-01-25
  • 打赏
  • 举报
回复
mark
yutaooo 2009-01-24
  • 打赏
  • 举报
回复

1.
只有非静态的函数的局部变量是在栈上分配的。
静态的局部变量,全局变量,都不是分配在栈上,也不在堆上。一般在 .data .rodata .bbs 中。
通过malloc / new 的对象在堆上进行分配。

这也就是说,对象并非“不是在栈上就是在堆上”,因为它可能在其他地方(.data .rodata .bbs)

2.
程序启动,会预先分配一块默认大小的栈。VC一般设置这个大小是 1M。当然也可以通过编译选项改变它,比如改成 2M
因为栈是有大小的。因此它有可能会溢出。不恰当的递归函数很容易就让栈溢出。这时候就应该考虑用堆。

堆可以认为是无限大的。当然计算机有内存限制,有指针大小限制,并不存在无限大。但是,这个大小只是受机器限制,所以可以认为足够大。虽然不是很精确,但是这样这样的理解是正确的方向。精确的描述,应该是,受限于操作系统如何布局进程,这个你要查具体操作系统的内容。
xiaoyisnail 2009-01-24
  • 打赏
  • 举报
回复
就根据你的需求来在栈或者堆上分配啊
栈上的就是函数实参,函数返回地址,函数内局部对象这些函数调用时分配的数据
c++更建议用引用而不是指针,引用或指针相对直接用对象减少了很多内存复制上的开销,不过用指针带了内存管理上的问题,所以c++中更多的应该学会使用引用
waizqfor 2009-01-24
  • 打赏
  • 举报
回复

Every process has 4 segments, data, text, stack, and heap.

Data segment is for global, static data member, as well as static variable in a function. So, in your example, a, pl, and d are in data segment.

Text segment is for code, all the compile generated (corresponding to your source code) code stored in this are.

Stack is for local variables as well as the activation record of function call. So, c and p2 of your example are in this area. Activation recrod includes at least returning address, return value, and parameter. So, the parameter b of function f is in this area.

Heap is for dynamically allocated memory (many OS put the shared library here as well). In your example, you did not show any code that dynamically allocate memory for pl and p2. If you do, the memory pointer by pl and p2 will be in heap, for example:
pl = new int;
p2 = (int*)malloc(sizeof(int));

It is important to remember that pl and p2 themself are not in heap but the memory they point to might.

  • 打赏
  • 举报
回复
网上很多讲堆和栈的
yutaooo 2009-01-24
  • 打赏
  • 举报
回复

修订2个错误。

1. 应该是bss而不是bbs 。。。。。
2. 应该是 参数和非静态局部变量在栈中分配而不仅仅是非静态局部变量。

64,647

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧