0.1代码的内存消耗

代码的内存消耗

1.C++内存分为四个区:

  • 代码区: 存放函数体的二进制代码。
  • 全局区(静态区,常量区): 全局变量和静态变量都存储在全局区,全局对象在程序启动时创建,程序结束时销毁;局部static在第一次使用时被创建,在程序结束时销毁。
  • 栈区: 栈区用来存放局部变量,局部变量在块内所定义的地方被创建,在离开块时被销毁。
  • 堆区: 堆区用来存放动态内存,动态内存对象的生存期被程序控制,必须程序员自己区销毁它。

内存四区地址的分配如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JgIcUVDd-1632403043835)(C:\Users\ThinkStation K\AppData\Roaming\Typora\typora-user-images\image-20210923175602093.png)]

2.C++的内存管理

我们写的C++程序运行时所需的内存空间分为固定部分可变部分:

C++内存空间

固定部分的内存消耗时是不会随着代码运行产生变化的,可变部分则是会产生变化的。 更具体一些,一些由C++编译的程序占用的内存分为以下几个部分:

  • 栈区:由编译器自动分配释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。
  • 堆区: 一般由程序员分配释放,若程序员不自己释放,程序结束时由os收回
  • 未初始化数据区: 存放未初始化的全局变量和静态变量。
  • 初始化数据区: 存放已经初始化的全局变量和静态变量。
  • 程序代码区: 存放函数体的二进制代码。

固定部分代码区和数据区所占内存都是固定的,而且占用空间非常小,那么看运行时消耗的内存主要是看可变部分

在可变部分中,栈区间的数据在代码块执行结束之后,系统会自动回收,而堆区间数据是需要程序员自己回收,所以也就是造成内存泄漏的发源地。

3.如何计算程序占用多大内存

想要算出程序会占用多少内存就要了解自己定义的数据类型的大小,如下:

C++数据类型的大小

为什么32位编译器指针占4个字节,而64位编译器指针占8个字节?

因为1个字节占8个比特,4个字节占32比特,可存放数据大小为2^32 ,即4G空间大小,即可以寻找4G空间大小的内存地址。 64位操作系统同理,可存放数据大小为2^64,即16777216TB空间(但由于主板和cpu限制电脑所支持内存一般最大只有16GB)。

由于现在使用的计算机都是64位,使用内存都超过了4GB,因此64位编译器使用8个字节的指针才能寻找所有内存地址。

4.内存对齐

内存对齐的两个原因:

  1. 平台原因不是所有硬件平台都能访问任意内存地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。为了同一个程序可以在多平台上运行,需要内存对齐
  2. 硬件原因:经过内存对其后,CPU访问内存的速度大大提升

看如下例子:

struct node{
   int num;
   char cha;
}st;
int main() {
    int a[100];
    char b[100];
    cout << sizeof(int) << endl;
    cout << sizeof(char) << endl;
    cout << sizeof(a) << endl;
    cout << sizeof(b) << endl;
    cout << sizeof(st) << endl;
}

输出结果为:

4
1
400
100
8       //num一个是int型,一个是char型,所占字节数应该是5,这里确是8,就是因为内存对其。

我们来看一下内存对齐和非内存对其产生的效果区别:

CPU读取内存不是一次读取单个字节,而是一块一块的来读取内存,块的大小可以是2,4,8,16个字节,具体取多少取决于硬件。

假设CPU内存划分为4字节大小的块要读取一个4字节大小的int型数据,来看一下这两种情况下CPU的工作量。

内存对齐的情况,如图:

内存对齐

一字节的char占用了4个字节,空了3个字节的内存地址,int数据从地址4开始。

此时,直接将地址4,5,6,7处的四个字节数据读取即可。

没有内存对齐的情况,如图:

非内存对齐

char型数据和int型数据挨在一起,该int数据从地址1开始,那么CPU想要读这个数据的话来看看需要几步操作:

  • 因为CPU是四个字节四个字节来寻址,首先CPU读取0,1,2,3处四个字节的数据
  • CPU读取4,5,6,7处的四个字节数据
  • 合并地址1,2,3,4处四个字节的数据才是本次操作需要的int数据
  • 此时一共需要两次寻址一次合并的操作。

虽然内存对齐浪费了内存资源,但由于计算机内存资源都是很充足的,我们更希望提高运行速度,而内存对齐后可以大大提高CPU访问内存的速度。

编译器一般都会做内存对齐的优化操作,因此,在考虑程序真正占用内存大小的时候,也需要认识到内存对齐的影响。

根据代码随想录为参考整理:https://programmercarl.com/%E5%89%8D%E5%BA%8F/%E5%88%B7%E4%BA%86%E8%BF%99%E4%B9%88%E5%A4%9A%E9%A2%98%EF%BC%8C%E4%BD%A0%E4%BA%86%E8%A7%A3%E8%87%AA%E5%B7%B1%E4%BB%A3%E7%A0%81%E7%9A%84%E5%86%85%E5%AD%98%E6%B6%88%E8%80%97%E4%B9%88%EF%BC%9F.html#%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
LBFGS(Limited-memory Broyden-Fletcher-Goldfarb-Shanno)是一种优化算法,常用于梯度下降方法中,尤其适合于解决大规模数据集的问题,因为它内存消耗小,适用于在线学习。在Python的机器学习库如scikit-learn、TensorFlow或PyTorch中,你可以使用它来训练模型。 这里是一个使用scikit-learn库中的`sklearn.optimize.minimize`函数,以LBFGS作为优化器训练简单线性回归模型的基本示例: ```python from sklearn.datasets import make_regression from sklearn.linear_model import LinearRegression from sklearn.optimize import minimize # 创建一个简单的数据集 X, y = make_regression(n_samples=100, n_features=10, noise=0.1) # 定义线性模型 model = LinearRegression() # 定义损失函数,通常是最小二乘法 def mse_loss(params): model.coef_ = params[:10] # 假设参数为10维 model.intercept_ = params[10] return 'mean_squared_error', (y - model.predict(X)).mean() ** 2 # 使用LBFGS优化器 initial_params = [0] * (10 + 1) # 初始化模型参数 res = minimize(mse_loss, initial_params, method='L-BFGS-B') # 打印结果 print(res) ``` 在这个例子中,`minimize`函数接收一个损失函数和初始参数,方法选择为LBFGS。函数返回一个`OptimizeResult`对象,包含了最优解和一些统计信息。 相关问题: 1. 在实际应用中,如何根据具体模型调整LBFGS的参数? 2. LBFGS与其他优化器(如SGD、Adam)相比,有何优势和适用场景? 3. 如何在处理大型神经网络时优化内存消耗,以更好地使用LBFGS?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值