在C/C++中,我们可以在堆栈或堆上存储变量,函数,成员函数,类的实例.
每个如何实施?如何管理(高级别)?gcc是否预先分配了一大块内存用于堆栈和堆,然后根据请求发送?原始内存来自RAM吗?
可以在堆而不是堆栈上分配函数吗?
我真的在询问堆和堆栈存储器的实现和管理.在阅读引用的问题后,我找不到任何解决这个问题的方法......感谢链接
我正在为我的数据组织决赛学习,我正在研究堆栈和堆,因为我知道它们将进入决赛,我将需要了解差异。我知道堆栈是什么,堆是什么。
但是我对堆栈是什么和堆是什么感到困惑。
堆栈是 RAM 中存储内存的地方,如果空间不足,就会发生堆栈溢出。对象默认存储在这里,当对象超出范围时它会重新分配内存,并且速度更快。
堆是 RAM 中存储内存的地方,如果空间不足,操作系统会分配更多空间。对于要存储在堆上的对象,需要使用 new 运算符来告知它,并且只有在告知后才会被释放。可能会出现碎片问题,它比堆栈慢,并且可以更好地处理大量内存。
但是什么是栈,什么是堆?它是存储内存的方式吗?例如静态数组或静态向量是堆栈类型和动态数组,链表是堆类型?
谢谢你们!
有如下代码:
int fun(){
char* pc = NULL;
{
char ac[100] = "addjfidsfsfds";
pc = ac;
}
...
pc[0] = 'd';
printf("%s\n", pc);
...
}
Run Code Online (Sandbox Code Playgroud)
那么,我可以pc在ac结束范围之后安全使用吗?因为我不确定分配的堆栈内存是否ac会被编译器重新分配用于其他用途.
在堆栈的末尾,有一个保护页被映射为不可访问的内存——如果程序访问它(因为它试图使用比当前映射更多的堆栈),就会出现访问冲突。
_chkstk() 是一个特殊的编译器辅助函数,它
确保局部变量有足够的空间
即它正在做一些堆栈探测(这是一个LLVM 示例)。
这种情况是特定于 Windows 的。所以Windows有一些解决问题的方法。
让我们考虑 Linux(或其他一些类 Unix)下的类似情况:我们有很多函数的局部变量。第一个堆栈变量访问在堆栈段后面(例如mov eax, [esp-LARGE_NUMBER],这里 esp-LARGE_NUMBER 是堆栈段后面的内容)。是否有任何功能可以防止可能的页面错误或 Linux(可能是其他类 Unix)或开发工具(如gcc、clang等)中的任何功能?-fstack-check(GCC 堆栈检查)是否以某种方式解决了这个问题?这个答案表明它与_chkstk().
PPS 一般来说,问题是关于操作系统(最重要的Linux与 Windows)之间的实现差异,这些方法与大量堆栈变量作斗争,爬到堆栈段后面。添加 C++ 和 C 标记是因为它是关于 Linux 本地二进制生成的,但汇编代码与编译器相关。
堆栈是在运行时还是编译时分配的?
例:
void main()
{
int x;
scanf("%d", &x);
int arr[x];
}
Run Code Online (Sandbox Code Playgroud) 功能的原型ctime是
char *ctime(const time_t *timep);
Run Code Online (Sandbox Code Playgroud)
我们可以看到,它返回一个字符串.但是,哪里有刺痛?
为什么我们不应该释放字符串的内存
这是示例代码将获得大量错误消息
char *p;
p = ctime(...);
...
free(p);
Run Code Online (Sandbox Code Playgroud)
***glibc检测到***./a.out:free():指针无效:0x00007f0b365b4e60***
有没有办法可以衡量一个函数使用多少堆栈内存?
这个问题并不特定于递归函数; 但我有兴趣知道递归函数会占用多少堆栈内存.
我有兴趣优化堆栈内存使用的功能; 然而,在不知道编译器已经进行了哪些优化的情况下,如果这是在做出真正的改进,那只是猜测.
需要明确的是,这不是关于如何优化以获得更好的堆栈使用的问题
那么是否有一些可靠的方法来找出函数在C中使用了多少堆栈内存?
注意:假设它不使用alloca或可变长度数组,应该可以在编译时找到它.
我发现代码来获取存储位置在本书变量锈要点中关于"栈和堆"第2章伊沃Balbaert:
let a = 32;
let mut b = "str";
println!({:p} {:p}, &a, &b);
Run Code Online (Sandbox Code Playgroud)
这本书有输出0x23fba4 0x23fb90,它说明第一个地址是堆栈中的位置,第二个地址是堆中的位置.
我对这个陈述有一些疑问,因为我听说堆栈地址越来越朝向减少内存地址.上面的第二个地址似乎是堆栈中的一个位置.
我错了吗?
引用:
现在,我们将运行以下程序并尝试可视化程序的内存://参见第2章/ code/references.rs
Run Code Online (Sandbox Code Playgroud)let health = 32; let mut game = "Space Invaders";值存储在内存中,因此它们具有内存地址.运行状况变量包含一个整数值32,它存储在位于0x23fba4的堆栈中,而变量游戏包含一个字符串,该字符串存储在从位置0x23fb90开始的堆中.(这些是我执行程序时的地址,但是在运行程序时它们会有所不同.)
绑定值的变量是指针或对值的引用.他们指向他们; 游戏是对太空入侵者的参考.值的地址由&运算符给出.因此,&health是存储值32的地址,&game是存储Space Invaders值的地址.我们可以使用格式字符串{:p}打印这些地址,如下所示:
Run Code Online (Sandbox Code Playgroud)println!("address of health-value: {:p}", &health); // prints 0x23fba4 println!("address of game-value: {:p}", &game); // prints 0x23fb90
Java 记录与 C# 结构类似吗?我的意思是,如果它们是堆栈分配的,而不是使用像类这样的引用,那么它们是在堆上分配的。
我正在阅读“计算机系统:程序员的视角,3/E”(CS:APP3e),以下代码是书中的示例:
long call_proc() {
long x1 = 1;
int x2 = 2;
short x3 = 3;
char x4 = 4;
proc(x1, &x1, x2, &x2, x3, &x3, x4, &x4);
return (x1+x2)*(x3-x4);
}
Run Code Online (Sandbox Code Playgroud)
书中给出了GCC生成的汇编代码:
long call_proc()
call_proc:
; Set up arguments to proc
subq $32, %rsp ; Allocate 32-byte stack frame
movq $1, 24(%rsp) ; Store 1 in &x1
movl $2, 20(%rsp) ; Store 2 in &x2
movw $3, 18(%rsp) ; Store 3 in &x3
movb $4, 17(%rsp) ; Store 4 in …Run Code Online (Sandbox Code Playgroud) stack-memory ×10
c ×6
heap-memory ×5
c++ ×2
gcc ×2
assembly ×1
heap ×1
java ×1
java-record ×1
linux ×1
pointers ×1
rust ×1
stack ×1
string ×1
x86-64 ×1