数据段、代码段、堆、栈详解

原文:https://blog.csdn.net/weixin_38233274/article/details/80321719
一 程序文件中的分区:
备注:只针对嵌入式,pc程序文件没有探究过。小标题“程序文件中的分区”其实不是很恰当,不知道该如何形容,此部分概念通常出现在一个程序编译完成后的大小统计,请自行理解。

相关概念:Code,RO_data,RW_data,ZI_data,RO,RW,常出现在嵌入式程序编译完成后的统计,例如MDK,IAR,ARM GCC。

有些技术文章中会直接使用RO,请注意区分RO和RO-data的区别。

Code:即代码域,它指的是编译器生成的机器指令。
RO_data:ReadOnly data,即只读数据域,它指程序中用到的只读数据,全局变量,例如C语言中const关键字定义的全局变量就是典型的RO-data。
RW_data:ReadWrite data,即可读写数据域,它指初始化为“非0值”的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。例如全局变量或者静态变量,且定义时赋予“非0值”给该变量进行初始化。
ZI_data:ZeroInitialie data,即0初始化数据,它指初始化为“0值”的可读写数据域,它与RW_data的区别是程序刚运行时这些数据初始值全都为0,而后续运行过程与RW-data的性质一样,它们也常驻在RAM区,因而应用程序可以更改其内容。包括未初始化的全局变量,和初始化为0的全局变量。
RO:只读区域,包括RO_data和code。

当程序存储在ROM中时,所占用的大小为Code + RO_data + RW_data 。
当程序执行时, RW_data和 ZI_data在RAM中,RO_data和code视cpu架构(51、arm、x86)不同处于ROM或者RAM中。其中ZI_data对应了BSS段,RW_data对应数据段,code对应代码段, RO_data对应数据段。

二 程序进程中的分区:
BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)若程序员不释放,则会有内存泄漏,系统会不稳定,Windows系统在该进程退出时由OS释放,Linux则只在整个系统关闭时OS才去释放(参考Linux内存管理)。

栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变 量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的后进先出特点,所以 栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

它是由操作系统分配的,内存的申请与回收都由OS管理。

PS:

全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存 于.data段中;而函数内的自动变量都在栈上分配空间。.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占 用,其内容由程序初始化,因此造成了上述情况。

bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小。

data(已手动初始化的数据)段则为数据分配空间,数据保存在目标文件中。 数据段包含经过初始化的全局变量以及它们的值。BSS段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面。当这个内存区进入程序的地址空间后全部清零。包含数据段和BSS段的整个区段此时通常称为数据区。

三. 总结
以上几个概念的对应关系如下表中所示:
备注:粉色部分的code和RO_data文字颜色为灰色,表示可能发生在ROM,也可能发生在RAM,根据架构不同而不同。
在这里插入图片描述

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,下面对代码进行分段详解。 ``` import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms ``` 这一段代码导入了PyTorch所需的模块,包括torch、torch.nn、torch.optim和torchvision.datasets等。 ``` # 定义超参数 batch_size = 64 learning_rate = 0.01 num_epochs = 10 ``` 这里定义了模型训练所需的超参数,包括batch_size、learning_rate和num_epochs。 ``` # 数据预处理 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) ``` 这里使用transforms模块对数据进行预处理,包括将图片转换为张量,以及对张量进行归一化操作。 ``` # 加载数据集 train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_dataset = datasets.MNIST(root='./data', train=False, transform=transform, download=True) test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False) ``` 这里使用datasets模块加载MNIST数据集,并使用DataLoader对数据进行批处理和打乱操作。 ``` # 定义模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.fc1 = nn.Linear(784, 256) self.fc2 = nn.Linear(256, 128) self.fc3 = nn.Linear(128, 10) def forward(self, x): x = x.view(-1, 784) x = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) x = self.fc3(x) return x model = Net() ``` 这里定义了一个三层全连接神经网络模型,包括输入层、隐藏层和输出层。输入层有784个神经元,隐藏层有256和128个神经元,输出层有10个神经元,对应着10个数字类别。在forward函数中,进行了前向传播操作。 ``` # 定义损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=learning_rate) ``` 这里定义了损失函数和优化器,使用交叉熵损失函数和随机梯度下降优化器。 ``` # 训练模型 for epoch in range(num_epochs): for i, (images, labels) in enumerate(train_loader): # 前向传播 outputs = model(images) loss = criterion(outputs, labels) # 反向传播 optimizer.zero_grad() loss.backward() optimizer.step() if (i+1) % 100 == 0: print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}' .format(epoch+1, num_epochs, i+1, len(train_loader), loss.item())) ``` 这里进行了模型训练,使用enumerate函数遍历DataLoader中的每个batch。对于每个batch,进行了前向传播、计算损失、反向传播和优化器更新参数的操作。在训练过程中,每100个batch输出一次损失。 ``` # 测试模型 model.eval() with torch.no_grad(): correct = 0 total = 0 for images, labels in test_loader: outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Accuracy of the network on the 10000 test images: {} %'.format(100 * correct / total)) ``` 这里对模型进行测试,首先使用model.eval()将模型设为评估模式,然后使用torch.no_grad()禁用梯度计算。对于测试集中的每个batch,进行了前向传播、计算预测值和计算准确率的操作。最后输出模型在测试集上的准确率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值