C++ Difference between global and non-global arrays (Stackoverflow Exception) [duplicate] - c++

This question already has an answer here:
Why does a large local array crash my program, but a global one doesn't? [duplicate]
(1 answer)
Closed 4 years ago.
When I write the following program, it works correctly i.e. the bitset array is declared outside the main() method.
Correctly Works
#include <iostream>
#include <bitset>
using namespace std;
bitset<5000> set[5000];
int main(){
cout<<"program runs fine"<<endl;
return 0;
}
But I get stack-overflow exception when I create it inside the main method. Can anyone explain in detail as to what is going on here? Normally I see stack-overflow exceptions in recursive methods. So who is using the stack here?
#include <iostream>
#include <bitset>
using namespace std;
int main(){
bitset<5000> set[5000];
cout<<"program runs fine"<<endl;
return 0;
}
Doesn't work and throws stack-overflow exception

Declaring it in main is declaring it in "automatic storage" AKA the stack. Declaring it outside of main, is declaring it in "static storage" AKA global data. You are declaring a ton of data. std::bitset<5000> is 632 bytes on my system with VS2013 (likely an alignment from 5000/8). And you are declaring 5000 of them. 5000 * 632 = 3 160 000 bytes, or roughly 3 Megabytes. Default in VS2013 is 1 megabyte for the stack, which is why you are seeing an overflow.
There are three kinds of storage: automatic, storage, and dynamic. These are colloquially referred to as stack, static (in some cases, global) and heap memory respectively:
int static_int;
int main() {
int automatic_int;
static int local_static_int; // also static storage!
int * dynamic_int_ptr = new int;
}
Automatic storage is allocated at a mix of compile time/run time. The stack expands at run-time entry to a function in order to hold local variables, but this is a known compile-time value since the number of variables and their sizes are well known (I'm ignoring dynamic arrays here because they are non-standard) These variables are constructed on scope entry, and destructed on scope exit.
Static storage is allocated at compile time. This memory is paid for up front, and constructed at program start. It is destructed when the program exits.
Dynamic storage is allocated at run-time. This memory is allocated by new and a pointer to some blob that holds your shiny new data is returned. These variables are constructed when new is called, and destructed when delete is called.

Because when you declare array as global, memory is allocated in the data segment of the process while when you try to declare it inside a function, memory is allocated on the stack. Since you are allocating large amount of memory, it results in stackoverflow exception.
Edit: Here is good explanation of the memory allocation.

You are trying to create (5000*5000)/8 bytes - 3Megs of data on the program stack which is causing a Stack Overflow as reported. You do not have enough stack space in your program for this. When you create it as a global, it is inserted in your programs data segment.

Related

In which memory section does the uninitialized variable integer 'A' occupy memory?

In the code below, on printing the size of the variable, it says 4 bytes using GCC compiler on my 64 bit Linux system. So, memory seems to be allocated to this undeclared integer. In which memory section does the uninitialized variable integer 'A' occupy memory? Would it be BSS segement as it is uninitialized or stack as it is a local variable? Though it is uninitialized it has default value zero and size of 4 bytes, so I was thinking it would get memory allocation on stack.
#include<iostream>
#include<iomanip>
using namespace std;
int main(void)
{
int A;
cout << A << endl << sizeof(A);
return 0;
}
Programs usually have 4 sections of memory i.e.
1. Code : This is where the executable instructions of a program are stored.
2. Data : This contains global and static variables that are initialized by programmer.
3. Stack: This is where all the local variables of all functions go along with their declarations, initializations and changes if any. It works on FILO or LIFO.
4. Heap: This is where dynamic memory allocation takes place. In c, you can use malloc to allocate memory on heap to a pointer and in c++ you can use new.
In your case, since A is just a local variable of the main function, therefore, it should be stored in stack.

Large arrays on local variables work on Linux but not on Windows [duplicate]

This question already has answers here:
Segmentation fault on large array sizes
(7 answers)
Closed 3 years ago.
Program with large global array:
int ar[2000000];
int main()
{
}
Program with large local array:
int main()
{
int ar[2000000];
}
When I declare an array with large size in the main function, the program crashes with "SIGSEGV (Segmentation fault)".
However, when I declare it as global, everything works fine. Why is that?
Declaring the array globally causes the compiler to include the space for the array in the data section of the compiled binary. In this case you have increased the binary size by 8 MB (2000000 * 4 bytes per int). However, this does mean that the memory is available at all times and does not need to be allocated on the stack or heap.
EDIT: #Blue Moon rightly points out that an uninitialized array will most likely be allocated in the bss data segment and may, in fact, take up no additional disk space. An initialized array will be allocated statically.
When you declare an array that large in your program you have probably exceeded the stack size of the program (and ironically caused a stack overflow).
A better way to allocate a large array dynamically is to use a pointer and allocate the memory on the heap like this:
using namespace std;
int main() {
int *ar;
ar = malloc(2000000 * sizeof(int));
if (ar != null) {
// Do something
free(ar);
}
return 0;
}
A good tutorial on the Memory Layout of C Programs can be found here.

Initiate array (size:20000001) inside main function throws SIGSEGV [duplicate]

This question already has answers here:
Segmentation fault on large array sizes
(7 answers)
Closed 3 years ago.
Program with large global array:
int ar[2000000];
int main()
{
}
Program with large local array:
int main()
{
int ar[2000000];
}
When I declare an array with large size in the main function, the program crashes with "SIGSEGV (Segmentation fault)".
However, when I declare it as global, everything works fine. Why is that?
Declaring the array globally causes the compiler to include the space for the array in the data section of the compiled binary. In this case you have increased the binary size by 8 MB (2000000 * 4 bytes per int). However, this does mean that the memory is available at all times and does not need to be allocated on the stack or heap.
EDIT: #Blue Moon rightly points out that an uninitialized array will most likely be allocated in the bss data segment and may, in fact, take up no additional disk space. An initialized array will be allocated statically.
When you declare an array that large in your program you have probably exceeded the stack size of the program (and ironically caused a stack overflow).
A better way to allocate a large array dynamically is to use a pointer and allocate the memory on the heap like this:
using namespace std;
int main() {
int *ar;
ar = malloc(2000000 * sizeof(int));
if (ar != null) {
// Do something
free(ar);
}
return 0;
}
A good tutorial on the Memory Layout of C Programs can be found here.

Why is this code giving runtime segmentation fault? [duplicate]

This question already has answers here:
Stack overflow visual C++, potentially array size?
(2 answers)
Closed 9 years ago.
Why is this code giving segmentation fault? I am using code::blocks.
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int a[555555];
}
This is what called stack overflow.
Generally stack size are small and you can't allocate memory in such a large amount on stack.
For this purpose programmers allocate it on heap (using dynamic allocation). In C, you can use malloc family function
int *a = malloc(sizeof(int)*55555); // Use free(a) to deallocate
In C++ you can use new operator
int *b = new int[555555]; // Use delete [] to deallocate
Because you are trying to allocate a bit over 2MB (Previously I failed at math and thought it was 2GB) of memory on stack, which then blows the stack.
Note: for windows the default stack size for a particular thread is 1MB and on Gnu/linux you can find out stack size value using ulimit -s command.
You've come to the right place to ask the question. ;)
The array is large and lives on the stack. The code crashes because it runs out of the limited stack space.
If you allocate a on the heap, the problem will likely disappear.
As other already had told you you are trying to allocate a large amount of memory in the stack which space is usually very limited.
See for instance:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int a[555555];
int* b = new int[555555];
delete [] b;
}
In that snipped, you have two arrays of integers, one allocated in the heap and the other allocated on the stack.
Here you can find some explanations about which are the differences between the heap and the stack:
What and where are the stack and heap?
http://gribblelab.org/CBootcamp/7_Memory_Stack_vs_Heap.html
I've got some considerations on your code.
First, modern compilers will recognize that a is unused and then it'll be thrown away.
But if you put a certain value into a certain position, a will be allocated, even though it's bigger than the stack size. The kernel will not allow you do that: that's why you get a SIGSEGV.
Finally, you should rely on either std::array or std::vector rather than pure C arrays.

How to find if a variable is allocated in stack or heap?

Stumbled upon this interview question somewhere,
In C,
Given a variable x, how do you find out if the space for that variable is allocated on the stack or heap?
(Is there any way to find it out programatically and not having to go through the symbol table, etc? And does finding if the space is allocated in stack or heap has any practical implications?)
No, not in general.
Do you know of gcc -fsplit-stack ?
It is up to the implementation to decide whether to allocate a contiguous stack or a stack where blocks are interleaved with heap blocks in memory. Good luck figuring out whether a block was allocated for the heap or the stack when the latter is split.
If you are working on an architecture that stores the stack on a larger address than the heap, you could compare the variable address with the bottom of the stack. Using the pthread threading API, this comparison would look like this:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <inttypes.h>
int is_stack(void *ptr)
{
pthread_t self = pthread_self();
pthread_attr_t attr;
void *stack;
size_t stacksize;
pthread_getattr_np(self, &attr);
pthread_attr_getstack(&attr, &stack, &stacksize);
return ((uintptr_t) ptr >= (uintptr_t) stack
&& (uintptr_t) ptr < (uintptr_t) stack + stacksize);
}
The test:
int main()
{
int x;
int *p1 = malloc(sizeof(int));
int *p2 = &x;
printf("%d %d\n", is_stack(p1), is_stack(p2));
return 0;
}
...prints 0 1, as expected.
The above code will not detect storage from stacks in other threads. To do that, the code would need to track all created threads.
This is NOT guaranteed by any standard BUT
on most platforms the stack grows down from highest address available, and heap grows up from the bottom if the most significant byte of the address is in the top half of the available memory space for your platform, and you haven't allocated gigabytes of memory, it's a pretty good bet it's on the stack.
#include <iostream>
#include <stdlib.h>
int main()
{
int x = 0;
int* y = new int;
unsigned int a1 = (int) &x;
unsigned int a2 = (int) y;
std::cout<<std::hex<<a1<<" "<<a2<<std::endl;
}
gives the output ffbff474 21600 on the machine I'm typing this.
It might be a trick question. Variables have either automatic or static storage duration[*]. You can fairly safely say that automatics are allocated "on the stack", at least assuming they aren't optimized into registers. It's not a requirement of the standard that there be "a stack", but a conforming C implementation must maintain a call stack and associate automatic variables with the levels of the call stack. So whatever the details of what it actually does, you can pretty much call that "the stack".
Variables with static storage duration generally inhabit one or more data sections. From the POV of the OS, data sections might be allocated from the heap before the program starts, but from the POV of the program they have no relation to the "free store".
You can tell the storage duration of a variable by examining its definition in the source -- if it's in function scope then it's automatic unless marked static. If it's not in function scope then it has static duration regardless of whether or not it is marked static (since the static keyword means something different there).
There is no portable way to tell the storage duration of a variable from its address, but particular implementations might provide ways to do it, or tools that you can use with greater or lesser reliability to take a guess.
Objects can also have dynamic storage duration (which generally is what "allocated on the heap" is intended to mean), but such objects are not variables, so that would be the trick if there is one.
[*] Or thread-local in C11 and C++11.
I don't think it has solutions. The code may adjust var's address by stack(heap) address scope, but it's would not be an exact way. At most, the code can only run in some certain platforms.
No it's not possible to determine that by memory location, the compiler would have to support it with isstack() to be portable.
One possible way to track memory allocation SPECIFICALY ON THE HEAP in C++ is overloading the new operator to keep tracking that for you. Then you know that if the memory is not allocated on the heap, it must be allocated on the stack.
#include <iostream>
#include <string>
// Variable to track how many allocations has been done.
static uint32_t s_alloc_count = 0;
void* operator new(size_t size){
s_alloc_count++;
std::cout << "Allocating " << size << " bytes\n";
return malloc(size);
}
Tracking the variable s_alloc_count you should be capable of see how many allocations on the heap has been done and have the size of these allocations printed on the console. Using debug tools like breakpoints, running the code "step-by-step" and console logging is one way to track where are these allocations. This is not an automated way but is a way to do that.
OBS: This tip should be only used for tests, avoid this type of code in production code.