C/C++(内存管理)

内存管理

进程空间

源程序:源代码

程序(可执行文件):有源程序编译后的文件

进程:时间概念,可执行文件被拉起到结束的这段过程。进程可以被拉起多个。

进程空间:可执行文件被拉起,在内存中的分布情况。

进程空间的分布:

stack
heap
data
>未初始化
>初始化
text

32位机最大寻址3G,

重点栈,堆

栈:auto修饰的变量,谁调谁用,用完即消。不需要人工干预。(入栈与出栈的关系),栈溢出。主要用于数据的交换,为不是适用于大空间的申请使用(大数据的申请用堆)

。大小不超过10M,避免大量的递归。

发展方向:由高到低先定义的在高位上,后申明的在低位上。

堆:可以存放任意类型的数据类型,但需要自己申请使用与释放。

申请:malloc();

释放:free();

大小:大空间。

发展方向:由低到高

char * p = (char*)molloc(1024*1024*1024);//加内存可解决
strcpy(p,"adbksj");
printf("sjdkjfk");
free(p);

申请mallloc以字节为大小

基本类型的申请

int * p = (int*)malloc(1*sizeof(int));//申请int类型的4个字节的大小
*p = 100;//初始化
printf("*p = %d\n",*p);//100

构造类型--数组的申请:

申请和初始化的最小单位均是字节

memset(p,0,sizeof(int))初始化

int arr[10];
int *p = (int*)malloc(10*sizeof(int));
memset(p,0,10*sizeof(int));//初始化,p:首地址,0:初始化元素,后面是大小
for(int i = 0;i < 10;i++) {
    printf("%d\n",p[i]);//不知道的值,不能使用*p++
}
free(p);

calloc()

int *p = (int *)calloc(10,sizeof(int));//10个4个单元的大小
for(int i = 0;i < 10;i++) {
    printf("%d\n",p[i]);//自动初始化了
}

realloc()扩容

char * pa = (char*)malloc(10);
strcpy(pa,"1234567890abcdef");//实际数据大于了申请的空间,这时候使用realloc();
char *pa = (char*)malloc(10);
char *newPa;
newPa = realloc(pa,20);
strcpy(newPa,"1234567890abcdef");
//newPa与pa有时候会不一样
free(newPa);

或者

char *pa = (char*)malloc(10);
pa = realloc(pa,20);
strcpy(pa,"1234567890abcdef");
//newPa与pa有时候会不一样
free(pa);

realloc()有两种情况,一种是空间不足在后买你继续扩充,另一种是开辟的空间不足,重新开辟足够的空间,把数据复制过去。

应用模型

#include<stdio.h>
#include<stdlib.h>
int main() {
    int *pa;
    int len;
    printf("please new len:");
    scanf("%d",&len);

    pa = (int*)malloc(len*sizeof(int));
    int oldlen = len;
    for(int i = 0;i<len;i++) {
        pa[i] = 100+i;
        printf("%d\n",pa[i]);
    }
    printf("please large len:");
    scanf("%d",&len);
    pa = (int*)realloc(pa,len*sizeof(int));
    for(int i = 0;i<len;i++) {
        if(oldlen <= i)
            pa[i] = 200+i;
        printf("%d\n",pa[i]);
    }
    printf("please small large len:");
    scanf("%d",&len);
    pa = (int*)realloc(pa,len*sizeof(int));
    for(int i = 0;i<len;i++) {
        printf("%d\n",pa[i]);
    }
    free(pa);

    return 0;
}

常见问题解析

错误模型一:在服务器模型中,常用到大循环,在大循环中未释放原有空间,重新申请新空间,造成原有空间内存泄漏。

while(1) {
    char *pa = (char*)malloc(100);
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    printf("ooooooooooooo\n");
    pa = (char*)malloc(100);//前面申请之后没有释放,重新申请
    //第一次申请,没有释放,在内存中占有空间,第二次给同一变量再次申请,前一次的空间没有释放。同样占有内存空间。释放要配对使用。两次使用free();也会挂机。malloc多余free会挂机,free对于malloc也会挂机。
}

置空与判空

对内存使用的逻辑:申请,判空,使用,释放,常见错误:释放以后未置空为NULL再次做判空使用或者释放以后继续菲方使用。

char *pc = (char*)malloc(100);//申请
if(pc == NULL) {
    printf("error\n");//内存里已经没有空间了
    exit(-1);
}
strcpy(px,"afakjfklajflkfja");//使用
free(pc);//释放
pc = NULL;//置空

谁申请谁释放,防止多次释放

void func(char*p) {
    printf("%s\n",p);
    free(p);
    p = NULL;
}
int main() {
    char *p = (char*)malloc(100);
    if(NULL == p) {
        exit(-1);
    }
    strcpy(p,"adajsfkljlk");
    func(p);
    free(p);
    p = NULL;
//会挂机,func中无需释放,谁申请谁释放

    return 0;
}

开放的地址空间

void foo() {
    printf("p = %s\n",p);
}
void func() {
    printf("p = %s\n",p);
}
int main() {
    char *p = (char*)malloc(100);
    strcpy(p,"afkajfklj");
    func(p);
    foo(p);

    return 0;
}
//p属于同一个变量,但是属于不同空间。p地址在不同的作用域中是共同开放的。

堆与栈空间的返回

栈空间不可以返回,堆空间可以返回。

1.只可以返回

2.地址也可以返回,返回来的地址不要去使用

3.谁用谁开,用完即消,不可以返回----栈

4.堆上的空间是可以返回的

int func() {
    int a = 500;
    return a;
}
int* foo() {
    int a = 500;
    /*
    printf("&a = %p\n",pa);windows下不行
    */
    int *pa = &a;
    printf("&a = %p\n",pa);

    return pa;
}
int *func2() {//谁用谁开,用完即消,不可以返回----栈
    int arr[100];
    return arr;
}
int main() {
    int a = func();//可以返回
    printf("a = %d\n",a);

    int *pa = foo();//地址可以返回,空间消失了。
    printf("pa = %p\n",pa);
    return 0;
}

堆的返回

char * getFormatMem(int size,char content) {
    char *p = (char*)malloc(size*sizeof(char));
    if(NULL == p)
        exit(-1);
    memset(p,content,size*sizeof(char)-1);
    p[size*sizeof(char)-1] = ‘\0‘;

    return p;
}
int main() {
    char *p = getFormatMem(100,‘a‘);//包装好的申请
    printf("p = %s\n",p);
    free(p);//释放,

    return 0;
}

原文地址:https://www.cnblogs.com/intelwisd/p/8326020.html

时间: 2024-11-06 11:25:46

C/C++(内存管理)的相关文章

linux内存管理

一.Linux 进程在内存中的数据结构 一个可执行程序在存储(没有调入内存)时分为代码段,数据段,未初始化数据段三部分:    1) 代码段:存放CPU执行的机器指令.通常代码区是共享的,即其它执行程序可调用它.假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段.     2) 数据段:存放已初始化的全局变量.静态变量(包括全局和局部的).常量.static全局变量和static函数只能在当前文件中被调用.     3) 未初始化数据区(uninitializeddata s

Block内存管理实例分析

在ios开发中,相信说道block大家都不陌生,内存管理问题也是开发者最头疼的问题,网上很多讲block的博客,但大都是理论性多点,今天结合一些实例来讲解下. 存储域 首先和大家聊聊block的存储域,根据block在内存中的位置,block被分为三种类型: NSGlobalBlock NSStackBlock NSMallocBlock 从字面意思上大家也可以看出来 NSGlobalBlock是位于全局区的block,它是设置在程序的数据区域(.data区)中. NSStackBlock是位于

Obstack是C标准库里面对内存管理的GNU扩展

Obstack介绍 Obstack初始化 在Obstack中申请对象 释放对象 申请growing object 获取Obstack状态 数据对齐 以下是来自wiki对obstack的介绍: Obstack是C标准库里面对内存管理的GNU扩展(实际上就是GNU C library了).Obstack===Object stack.没错,Obstack就是一个栈,栈里面的元素是对象object(不是面向对象的对象哦,这里的对象单指数据元素).这些数据是动态的,也就是使用的是动态内存.这种内存管理技

OC内存管理

OC内存管理 一.基本原理 (一)为什么要进行内存管理. 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等. 管理范围:任何继承NSObject的对象,对其他的基本数据类型无效. 本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也

39-oc集合中对象的内存管理

集合中对象的内存管理 集合的内存管理原则是什么 当把一个对象添加到集合中时,这个对象会做了一次retain操作,计数器会+1 当一个集合被销毁时,会对集合里面的所有对象做一次release操作,计数器会-1 当一个对象从集合中移除时,会对这个对象做一次release操作,计数器会-1 集合方法的普遍规律是什么 如果方法名是add\insert开头,那么被添加的对象,计数器会+1 如果方法名是remove\delete开头,那么被移除的对象,计数器-1

iOS基础 ----- 内存管理

Objective-C 的内存管理方式有引用计数机制,垃圾回收机制,自动释放池.有alloc,就有释放.iOS应?程序出现Crash(闪退),90%的原因是因为内存问 题.在?个拥有数?个甚?是上百个类的?程?,查找内存问 题极其困难,学会内存管理,能帮我们减少出错的?率.内存问题体现在两个??:内存溢出.野指针异常. 引用计数器 在Xcode4.2及之后的版本中由于引入了ARC(Automatic Reference Counting)机制,程序编译时Xcode可以自动给你的代码添加内存释放代

c++ 块内存管理

#pragma once   //头文件 #include<iostream> #include<string.h> #include<list> #include "TypeTraits.hpp"  //类型萃取 #include <stdarg.h> using namespace std; struct SaveAdapter//保存适配器 基类 { virtual void save(const char* fmt, ...) =

魏兆辉的IOS基础学习笔记之十二 OC语言基础-07 Foundation内存管理

本篇博文,将给大家介绍下再Objective-C中如何使用内存管理.一个程序运行的时候,如果不及时的释放没有用的空间内存.那么,程序会越来 越臃肿,内存占用量会不断升高.我们在使用的时候,就会感觉很卡,最终使得程序运行奔溃.因此,将无效的内存及时清理释放,是非常有必要的. 一个对象在最初创建使用,到最后的回收释放,经历的是怎样一个过程呢?包括:诞生(通过alloc或new方法实现).生存(接收消息并执行操作).交友(通过复合以及向方法传递参数).最终死去(被释放掉). 一.引用计数 在对象创建的

OC -内存管理

管理内存有三种方式 1:垃圾回收,在java中常见的管理内存方法,系统自动检测对象是否被使用,是否被释放 2.MRC: 手动管理引用计数,iOS管理内存的方式,程序员通过手动方式来管理对象是否被释放 3.ARC: 自动管理引用计数:基于MRC,系统自动的管理内存 引用计数:retainCount 当我们使用一个指针指向一块内存的时候,应该对这块内存做retain操作,引用计数+1.当我们不再使用这个指针指向这块内存,应该对这块内存做release操作,引用计数-1.这样可以使引用计数值一直保持等

linux内核探索之内存管理(四):对页表和页表项的操作

接上一节,主要参考<深入Linux内核架构>(3.3节),即linux-3.18.3 1. 对PTE的操作 最后一级页表中的项不仅包含了指向页的内存位置的指针,还在上述的多于比特位包含了与页有关的附加信息.尽管这些数据是特定于CPU的,它们至少提供了有关页访问控制的一些信息.下列位在linux内核支持的大多数CPU中都可以找到. arch/x86/include/asm/pgtable_types.h #define _PAGE_BIT_PRESENT 0 /* is present */ #