C++中4种管理数据内存的方式总结

目录
  • C++的4种管理数据内存的方式
    • 自动存储
    • 静态存储
    • 动态存储
    • 线程存储
  • 栈、堆、内存泄漏

根据用于分配内存的方法,C++中有3中管理数据内存的方式:自动存储、静态存储和动态存储(有时也叫做自由存储空间或堆)。在存在时间的长短方面,以这三种方式分配的数据对象各不相同。下面简要介绍这三种类型。

注:C++11中新增了第四种类型——线程存储

C++的4种管理数据内存的方式

自动存储

在函数内部定义的常规变量使用自动存储空间,被称为自动变量(automatic variable),这意味着它们在所属的函数被调用时自动产生,在该函数结束时消亡。例如,当在一个自定义的函数getname()中定义了一个temp数组时,temp数组仅当getname()函数活动时存在。当成许控制权回到main()时,temp使用的内存将自动被释放。如果getname()返回temp的地址,则main()中的name指针指向的内存将很快得到重新使用。这就是在getname()中使用new的原因之一。

实际上,自动变量是一个局部变量,其作用域为包含它的代码块。代码块是被包含在花括号中的一段代码。

自动变量通常存储在栈中。这意味着执行代码块时,其中的变量将依次加入到栈中,而在离开代码块时,将按相反的顺序释放着些变量,着被称为后进先出(LIFO)。因此,在程序执行过程中,栈将不断地增大和缩小。

静态存储

静态存储是整个程序执行期间都存在的存储方式。是变量称为静态的方式有两种:一种是在函数外面定义它;另一种是在声明变量时使用关键字statis:

static double fee = 56.50;

在K&R C中,只能初始化静态数组和静态结构,而C++ Release2.0(及后续版本)和ASNI C中,也可以初始化自动数组和自动结构。

注:自动存储和静态存储关键在于:这些方法严格地限制了变量的寿命。变量可能存在于程序的整个生命周期(静态变量),也可能只是在特定函数被执行时存在(自动变量)。

动态存储

new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内存池,这在C++中被称为自由存储空间(free store)或堆(heap)。该内存池同用于静态变量和自动变量的内存是分开的。new和delete让您能够在一个函数中分配内存,而在另一个函数中释放它。因此,数据的声明周期不完全收程序或函数的生命时间控制。与使用常规变量相比,使用new和delete让程序员对程序如何使用内存有更大的控制权。然而,内存管理也更复杂了。在栈中,自动添加和删除机制使得占用的内存总是连续的,单new和delete的相互影响可能导致占用的自由存储区不连续,这使得跟踪新分配内存的位置更困难。

线程存储

在多线程程序中,所有线程共享程序中的变量。Linux有一全局变量,所有线程都可以使用它,改变它的值。如果每个线程希望能单独拥有它,那么就需要使用线程存储了。表面上看起来这是一个全局变量,所有线程都可以使用它,但它的值在每一个线程中又是单独存储的。

线程存储的具体用法:

1.创建一个类型为pthread_key_t类型的变量。

2.调用pthread_key_create()来创建该变量,该函数有两个参数,第一个参数就是上面声明的 pthread_key_t变量,第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用,该函数指针可以设成NULL,这样系统将调用默认的清理函数;

3.当线程中需要存储特殊值的时候,可以调用pthread_setspcific(),该函数有两个参数,第一个为前面声明的pthread_key_t变量,第二个为void*变量,这样可以存储任何类型的值;

4.如果需要取出所存储的值,调用pthread_getspecific(),该函数的参数为前面提到的 pthread_key_t变量,该函数返回void*类型的值;

5.注销使用pthread_key_delete()函数,该函数并不检查当前是否有线程正在使用,也不会调用清理函数,而只是释放以供下一次调用pthread_key_create()使用。

下面是前面提到的函数原型:

int pthread_setspecific(pthread_key_t key, const void *value);
void* pthread_getspecific(pthread_key_t key);
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_key_delete(pthread_key_t *key);

线程存储例子:

#include <pthread.h>
#include <stdio.h>

static pthread_key_t thread_key;

void* thread_function(void* args)
{
    pthread_t spid = pthread_self();

    pthread_setspecific(thread_key, (void *)spid);

    pthread_t gpid = (pthread_t)pthread_getspecific(thread_key);

    printf("set: %lu, get: %lu, %s\n", spid, gpid, (spid == gpid ? "equal":"not equal"));

    return NULL;
}

int main(int argc, char** argv)
{
    int i;
    pthread_t threads[5];

    pthread_key_create(&thread_key, NULL);

    for (i = 0; i < 5; ++i) {
        pthread_create(&(threads[i]), NULL, thread_function, NULL);
    }

    for (i = 0; i < 5; ++i) {
        pthread_join(threads[i], NULL);
    }

    pthread_key_delete(thread_key);

    return 0;
}

栈、堆、内存泄漏

如果使用new在自由存储空间(或堆)上创建变量后,没有调用delete。会发生什么?

即使包含指针的内存由于作用域规则和对象生命周期的原因而被释放,在自由存储空间上动态分配的变量或结构依然存在。

实际上将会无法访问自由存储空间的结构,因为指向这些内存的指针无效。

这将导致内存泄露,被泄漏的内存在程序的整个生命周期将不可使用,这些内存被分配,但无法被使用。

到此这篇关于C++中4种管理数据内存的方式总结的文章就介绍到这了,更多相关C++数据内存内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++浅析数据在内存中如何存储

    目录 一.数据类型 二.原码反码补码 三.大小端 整型提升 一.数据类型 数据类型有7种: char            字符型     short          短整型    int               整型   long            长整型   long long    更长整型   float            单精度浮点数    double        双精度浮点数 二.原码反码补码 计算机中的整数有三种2进制表示方法,即原码.反码和补码. 三种表示方法均

  • C++数据结构之二叉搜索树的实现详解

    目录 前言 介绍 实现 节点的实现 二叉搜索树的查找 二叉搜索树的插入 二叉搜索树的删除 总结 前言 今天我们来学一个新的数据结构:二叉搜索树. 介绍 二叉搜索树也称作二叉排序树,它具有以下性质: 非空左子树的所有键值小于其根节点的键值 非空右子树的所有键值大于其根节点的键值 左,右子树都是二叉搜索树 那么我先画一个二叉搜索树给大家看看,是不是真的满足上面的性质. 我们就以根节点6为例子来看,我们会发现比6小的都在6的左边,而比6大的都在6的右边.对于6的左右子树来说,所有的节点都遵循这个规则.

  • C++集体数据交换实现示例讲解

    目录 一.说明 二.示例和代码 一.说明 到目前为止介绍的功能共享一对一的关系:即一个进程发送和一个进程接收.链接是通过标签建立的.本节介绍在多个进程中调用相同参数但执行不同操作的函数.对于一个进程,函数可能会发送数据,对于另一个进程,它可能会接收数据.这些功能称为集体操作. 二.示例和代码 示例 47.9.使用 gather() 从多个进程接收数据 #include <boost/mpi.hpp> #include <boost/serialization/string.hpp>

  • C++中4种管理数据内存的方式总结

    目录 C++的4种管理数据内存的方式 自动存储 静态存储 动态存储 线程存储 栈.堆.内存泄漏 根据用于分配内存的方法,C++中有3中管理数据内存的方式:自动存储.静态存储和动态存储(有时也叫做自由存储空间或堆).在存在时间的长短方面,以这三种方式分配的数据对象各不相同.下面简要介绍这三种类型. 注:C++11中新增了第四种类型——线程存储 C++的4种管理数据内存的方式 自动存储 在函数内部定义的常规变量使用自动存储空间,被称为自动变量(automatic variable),这意味着它们在所

  • Python中4种实现数值的交换方式

    目录 1.使用临时变量 2.使用tuple元组 3.使用 加减法 或 乘除法 4.使用异或运算 1.使用临时变量 该方法是最简单的,也是最容易理解的,适用于所有编程语言,其实现过程如下: tmp = a a = b b = tmp 2.使用tuple元组 该方法是Python下特有的方法,并且只需要一行代码即可实现,其使用到了元组(tuple),其大致原理如下: 右边的 b, a 会构成一个由 b 和 a 组成的元组对元组进行拆包,然后再分别赋值给到左边的 a, b a, b = b, a 我们

  • 基于Java中两种jersey文件上传方式

    本文将带领大家使用基于JAX-RS REST风格的实现Jersey来上传文件到服务器制定的文件夹,如果是图片并读取显示出该图片. 准备工作:准备一个form表单,有两个字段,一个是type="file"和type="text",并且表单需要使用POST方式提交.注意改表单需要使用multipart/form-data.该项目使用netbeans8.0和glassfish4.0开发和运行.并且使用maven管理该工程:需要在您的C盘建立一个文件夹,用来存储上传的文件.

  • JavaScript中三种异步上传文件方式

    异步上传文件是为了更好的用户体验,是每个前端必须掌握的技能.这里我提出三点有关异步文件上传的方式. 使用第三方控件,如Flash,ActiveX等浏览器插件上传. 使用隐藏的iframe模拟异步上传. 使用XMLHttpRequest2来实现异步上传. 第一种使用浏览器插件上传,需要一定的底层编码功底,在这里我就不讲了,以免误人子弟,提出这点大家可以自行百度. 第二种使用隐藏的iframe模拟异步上传.为什么在这里说的是模拟呢?因为我们其实是将返回结果放在了一个隐藏的iframe中,所以才没有使

  • 浅谈JS中几种轻松处理'this'指向方式

    我喜欢在JS中更改函数执行上下文的指向,也称为 this 指向. 例如,咱们可以在类数组对象上使用数组方法: const reduce = Array.prototype.reduce; function sumArgs() { return reduce.call(arguments, (sum, value) => { return sum += value; }); } sumArgs(1, 2, 3); // => 6 另一方面,this 很难把握. 咱们经常会发现自己用的 this

  • vue中data里面的数据相互使用方式

    目录 data里面的数据相互使用 具体代码如下 data里的数据不能相互引用问题 data里面的数据相互使用 今天在写代码的时候,遇到一个问题,我想使用data里面的一个对象使用data里面的某个数据,附图片: 我想让active的值给params对象里面的topicListType使用,我不想直接在一个方法里面改变这个值(想改的话就直接可以改了,太简单),所以就有了这个想法. 在data里面使用,但是肯定不能写成 this.params.topicListType: this.active,这

  • 详解Java虚拟机管理的内存运行时数据区域

    详解Java虚拟机管理的内存运行时数据区域 概述 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁. 程序计数器 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基

  • iOS中从网络获取数据的几种方法的比较

    IOS中获取网络数据一般有三种:1.NSURLCondition(已过时) 2.NSURLSession  3.三方库AFNetWorking NSURLSession 是苹果对NSULRCondition的替代品,NSURLSession比NSURLCondition多了 1.可配置的数据信息NSURLSessionConfiguration,NSURLSessionConfiguration使你可以设置你要请求的数据,通常的设置如缓存,也可以使用默认的配置信息defaultCongurati

  • java中List去除重复数据的5种方式总结

    前言 List 是一个接口,它继承于Collection的接口.它代表着有序的队列.当我们讨论List的时候,一般都和Set作比较. List中元素可以重复,并且是有序的(这里的有序指的是按照放入的顺序进行存储.如按照顺序把1,2,3存入List,那么,从List中遍历出来的顺序也是1,2,3). Set中的元素不可以重复,并且是无序的(从set中遍历出来的数据和放入顺序没有关系). 以下介绍五种-不同的方法去除 Java 中ArrayList中的重复数据 1.使用LinkedHashSet删除

  • 详细介绍在pandas中创建category类型数据的几种方法

    在pandas中创建category类型数据的几种方法之详细攻略 T1.直接创建 category类型数据 可知,在category类型数据中,每一个元素的值要么是预设好的类型中的某一个,要么是空值(np.nan). T2.利用分箱机制(结合max.mean.min实现二分类)动态添加 category类型数据 输出结果 [NaN, 'medium', 'medium', 'fat'] Categories (2, object): ['medium', 'fat']    name    ID

随机推荐