In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article introduces the relevant knowledge of "C language/C++ memory management". In the actual case operation process, many people will encounter such difficulties. Next, let Xiaobian lead you to learn how to deal with these situations! I hope you can read carefully and learn something!
I. Memory
In a computer, memory is independent of each other, and application A cannot access application B in general, although special techniques can be used, but this article does not explain in detail. For example, in a computer, a video player program and a browser program, their memory is not accessible, and the memory owned by each program is managed by partitions.
In a computer system, running program A will open up memory region 1 for program A, and running program B will open up memory region 2 for program B, logically separating memory region 1 from memory region 2.
1.1 Memory 4
Memory area 1 opened in program A will be divided into several areas, which are memory four areas, memory four areas into stack area, heap area, data area and code area.
Stack area refers to the area where temporary variables are stored. Temporary variables include local variables, return values, parameters, return addresses, etc. When these variables exceed the current scope, they will pop up automatically. The maximum storage of the stack is a fixed size, exceeding which will cause stack overflow.
Heap area refers to a relatively large memory space, mainly used for dynamic memory allocation; in program development, developers generally allocate and release, if not released at the end of the program, the system will automatically recycle.
Data area refers to the area where global variables, constants and static variables are mainly stored. Data area can be divided into global area and static area. Global variables and static variables will be stored in this area.
Code area is better understood, mainly to store executable code, the area's attributes are read-only.
1.2 Use code to verify the underlying structure of memory area 4
Because the underlying structure of stack area and heap area is relatively intuitive, only these two concepts are demonstrated in this code. First look at the memory address allocation in the code observation stack area:
#include int main() { int a = 0; int b = 0; char c='0'; printf("variable a address is: %d\n variable b address is: % d\n variable c address is: %d\n", &a, &b, &c); }
The results of the run were:
We can observe that the address of variable a is 2293324 and the address of variable b is 2293320, which is separated by 4 because int has a data size of 4; looking at variable c, we find that variable c has an address of 2293319, which is separated by 1 from the address of variable b 2293324, because c has a data type of char and a type size of 1. Here we observe that when I create variables, the order is a to b and then to c, why are the addresses between them not increasing but decreasing? That's because a data storage structure in the stack area is first-in-last-out, as shown in the figure:
首先栈的顶部为地址的"最小"索引,随后往下依次增大,但是由于堆栈的特殊存储结构,我们将变量 a 先进行存储,那么它的一个索引地址将会是最大的,随后依次减少;第二次存储的值是 b,该值的地址索引比 a 小,由于 int 的数据大小为 4,所以在 a 地址为 2293324 的基础上往上减少 4 为 2293320,在存储 c 的时候为 char,大小为 1,则地址为 2293319。由于 a、b、c 三个变量同属于一个栈内,所以它们地址的索引是连续性的,那如果我创建一个静态变量将会如何?在以上内容中说明了静态变量存储在静态区内,我们现在就来证实一下:
#include int main() { int a = 0; int b = 0; char c='0'; static int d = 0; printf("变量a的地址是:%d\n变量b的地址是:%d\n变量c的地址是:%d\n", &a, &b, &c); printf("静态变量d的地址是:%d\n", &d); }
运行结果如下:
以上代码中创建了一个变量 d,变量 d 为静态变量,运行代码后从结果上得知,静态变量 d 的地址与一般变量 a、b、c 的地址并不存在连续,他们两个的内存地址是分开的。那接下来在此建一个全局变量,通过上述内容得知,全局变量与静态变量都应该存储在静态区,代码如下:
#include int e = 0; int main() { int a = 0; int b = 0; char c='0'; static int d = 0; printf("变量a的地址是:%d\n变量b的地址是:%d\n变量c的地址是:%d\n", &a, &b, &c); printf("静态变量d的地址是:%d\n", &d); printf("全局变量e的地址是:%d\n", &e); }
运行结果如下:
从以上运行结果中证实了上述内容的真实性,并且也得到了一个知识点,栈区、数据区都是使用栈结构对数据进行存储。
在以上内容中还说明了一点栈的特性,就是容量具有固定大小,超过最大容量将会造成栈溢出。查看如下代码:
#include int main() { char arr_char[1024*1000000]; arr_char[0] = '0'; }
以上代码定义了一个字符数组 arr_char,并且设置了大小为 1024*1000000,设置该数据是方便查看大小;随后在数组头部进行赋值。运行结果如下:
这是程序运行出错,原因是造成了栈的溢出。在平常开发中若需要大容量的内存,需要使用堆。
堆并没有栈一样的结构,也没有栈一样的先进后出。需要人为的对内存进行分配使用。代码如下:
#include #include #include int main() { char *p1 = (char *)malloc(1024*1000000); strcpy(p1, "这里是堆区"); printf("%s\n", p1); }
以上代码中使用了strcpy 往手动开辟的内存空间 p1 中传数据"这里是堆区",手动开辟空间使用 malloc,传入申请开辟的空间大小 1024*1000000,在栈中那么大的空间必定会造成栈溢出,而堆本身就是大容量,则不会出现该情况。随后输出开辟的内存中内容,运行结果如下:
在此要注意p1是表示开辟的内存空间地址。
二、malloc 和 free
在 C 语言(不是 C++)中,malloc 和 free 是系统提供的函数,成对使用,用于从堆中分配和释放内存。malloc 的全称是 memory allocation 译为"动态内存分配"。
2.1 malloc 和 free 的使用
在开辟堆空间时我们使用的函数为 malloc,malloc 在 C 语言中是用于申请内存空间,malloc 函数的原型如下:
void *malloc(size_t size);
在 malloc 函数中,size 是表示需要申请的内存空间大小,申请成功将会返回该内存空间的地址;申请失败则会返回 NULL,并且申请成功也不会自动进行初始化。
细心的同学可能会发现,该函数的返回值说明为 void *,在这里 void * 并不指代某一种特定的类型,而是说明该类型不确定,通过接收的指针变量从而进行类型的转换。在分配内存时需要注意,即时在程序关闭时系统会自动回收该手动申请的内存 ,但也要进行手动的释放,保证内存能够在不需要时返回至堆空间,使内存能够合理的分配使用。
释放空间使用 free 函数,函数原型如下:
void free(void *ptr);
free 函数的返回值为 void,没有返回值,接收的参数为使用 malloc 分配的内存空间指针。一个完整的堆内存申请与释放的例子如下:
#include #include #include int main() { int n, *p, i; printf("请输入一个任意长度的数字来分配空间:"); scanf("%d", &n); p = (int *)malloc(n * sizeof(int)); if(p==NULL){ printf("申请失败\n"); return 0; }else{ printf("申请成功\n"); } memset(p, 0, n * sizeof(int));//填充0 //查看 for (i = 0; i < n; i++) printf("%d ", p[i]); printf("\n"); free(p); p = NULL; return 0; }
以上代码中使用了 malloc 创建了一个由用户输入创建指定大小的内存,判断了内存地址是否创建成功,且使用了 memset 函数对该内存空间进行了填充值,随后使用 for 循环进行了查看。最后使用了 free 释放了内存,并且将 p 赋值 NULL,这点需要主要,不能使指针指向未知的地址,要置于 NULL;否则在之后的开发者会误以为是个正常的指针,就有可能再通过指针去访问一些操作,但是在这时该指针已经无用,指向的内存也不知此时被如何使用,这时若出现意外将会造成无法预估的后果,甚至导致系统崩溃,在 malloc 的使用中更需要需要。
2.2 内存泄漏与安全使用实例与讲解
内存泄漏是指在动态分配的内存中,并没有释放内存或者一些原因造成了内存无法释放,轻度则造成系统的内存资源浪费,严重的导致整个系统崩溃等情况的发生。
内存泄漏通常比较隐蔽,且少量的内存泄漏发生不一定会发生无法承受的后果,但由于该错误的积累将会造成整体系统的性能下降或系统崩溃。特别是在较为大型的系统中,如何有效的防止内存泄漏等问题的出现变得尤为重要。例如一些长时间的程序,若在运行之初有少量的内存泄漏的问题产生可能并未呈现,但随着运行时间的增长、系统业务处理的增加将会累积出现内存泄漏这种情况;这时极大的会造成不可预知的后果,如整个系统的崩溃,造成的损失将会难以承受。由此防止内存泄漏对于底层开发人员来说尤为重要。
C 程序员在开发过程中,不可避免的面对内存操作的问题,特别是频繁的申请动态内存时会及其容易造成内存泄漏事故的发生。如申请了一块内存空间后,未初始化便读其中的内容、间接申请动态内存但并没有进行释放、释放完一块动态申请的内存后继续引用该内存内容;如上所述这种问题都是出现内存泄漏的原因,往往这些原因由于过于隐蔽在测试时不一定会完全清楚,将会导致在项目上线后的长时间运行下,导致灾难性的后果发生。
如下是一个在子函数中进行了内存空间的申请,但是并未对其进行释放:
#include #include #include void m() { char *p1; p1 = malloc(100); printf("开始对内存进行泄漏..."); } int main() { m(); return 0; }
如上代码中,使用 malloc 申请了 100 个单位的内存空间后,并没有进行释放。假设该 m 函数在当前系统中调用频繁,那将会每次使用都将会造成 100 个单位的内存空间不会释放,久而久之就会造成严重的后果。理应在 p1 使用完毕后添加 free 进行释放:
free(p1);
以下示范一个读取文件时不规范的操作:
#include #include #include int m(char *filename) { FILE* f; int key; f = fopen(filename, "r"); fscanf(f, "%d", &key); return key; } int main() { m("number.txt"); return 0; }
以上文件在读取时并没有进行 fclose,这时将会产生多余的内存,可能一次还好,多次会增加成倍的内存,可以使用循环进行调用,之后在任务管理器中可查看该程序运行时所占的内存大小,代码为:
#include #include #include int m(char *filename) { FILE* f; int key; f = fopen(filename, "r"); fscanf(f, "%d", &key); return key; } int main() { int i; for(i=0;i
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.