洛阳 网站建设公司,wordpress tree,什么网站上做效果图可以赚钱,一个网站完整的html代码文章目录 内存分区堆(heap)和栈(stack)的区别new和malloc的区别delete和free有什么区别 野指针导致野指针的原因如何避免野指针野指针和悬浮指针 内存对齐什么是内存对其为什么要内存对齐内存对其的规则 内存分区
从高地址到低地址依次是#xff1a;
栈(stack)区#xff1a… 文章目录 内存分区堆(heap)和栈(stack)的区别new和malloc的区别delete和free有什么区别 野指针导致野指针的原因如何避免野指针野指针和悬浮指针 内存对齐什么是内存对其为什么要内存对齐内存对其的规则 内存分区
从高地址到低地址依次是
栈(stack)区由编译器自动释放、分配。存放局部变量、形参和返回值堆(heap)区由程序员分配内存和释放。调用malloc()\new和free()\delete()全局(静态)区这部分可以细分为data区、bss区、常量区 .data区里主要存放的是已经初始化的全局变量、静态变量和常量.bss区主要存放的是未初始化的全局变量、静态变量这些未初始化的数据在程序执行前会自动被系统初始化为0或者NULL.rodata常量区是全局区中划分的一个小区域也被称为只读区.里面存放的是常量如const修饰的全局变量、字符串常量等 .text代码区存放函数体的二进制代码由操作系统进行管理的
堆(heap)和栈(stack)的区别
栈是⼀种有限的内存区域⽤于存储局部变量、函数调⽤信息等。 堆是⼀种动态分配的内存区域⽤于存储程序运⾏时动态分配的数据。
变量的生命周期栈上的变量⽣命周期与其所在函数的执⾏周期相同⽽堆上的变量⽣命周期由程序员显式控制可以使⽤ 或 malloc 和释放使⽤ delete 或 free 。
内存分配和释放速度栈上的内存分配和释放是⾃动的速度较快。⽽堆上的内存分配和释放需要⼿动操作速度相对较慢。
new和malloc的区别
类型安全
new是C的运算符可以为对象分配内存并调⽤相应的构造函数。malloc是C语⾔库函数只分配指定⼤⼩的内存块不会调⽤构造函数。
返回类型
new返回的是具体类型的指针⽽且不需要进⾏类型转换。malloc 返回的是 void* 需要进⾏类型转换因为它不知道所分配内存的⽤途。
释放内存的方式
new的对象用delete其会调⽤对象的析构函数然后释放内存。malloc的对象用free其会调⽤对象的析构函数然后释放内存
内存分配失败时的⾏为:
new在内存分配失败时会抛出 std::bad_allocmalloc 在内存分配失败时返回 NULL 。
内存块⼤⼩:
new可以⽤于动态分配数组并知道数组⼤⼩。malloc 只是分配指定⼤⼩的内存块不了解所分配内存块的具体⽤途。
delete和free有什么区别
类型安全性
delete会调用对象的析构函数确保资源被正确释放free不了解对象的构造和析构只是简单得释放内存块
内存块释放后的行为
delete释放的内存块的指针指会被设置为nullptr以避免野指针free不会修改指针的值可能导致野指针问题
数组的释放
delete可以正确释放通过new[]分配的数组free不会修改数组的大小不适用于释放通过malloc分配的数组。
野指针
野指针wild pointer是指指向内存中未知位置的指针即指针变量指向的地址没有被正确初始化或者指向的内存已经被释放但指针变量仍然保留了这个地址。这样的指针通常会导致未定义行为可能会导致程序崩溃、数据损坏或者其他不可预测的结果。
导致野指针的原因
未初始化的指针
当指针变量被声明但未被初始化时其值是未知的它可能指向任意内存地址。
int *ptr; // 未初始化的指针已释放或者销毁的指针
当指针变量指向的内存已经被释放或销毁但指针变量本身仍然保留了之前的地址。
int *ptr new int; // 为指针分配内存
delete ptr; // 释放指针所指向的内存
//此时 ptr 成为野指针因为它仍然指向已经被释放的内存
ptr nullptr; // 避免野指针应该将指针置为 nullptr 或赋予新的有效地址返回局部变量的指针
int* createInt()
{int x 10;return x;
}如何避免野指针 初始化指针始终确保在使用指针之前将其初始化为一个有效的地址或者 nullptr。 及时置空指针当指针所指向的内存不再需要时及时将指针置为空指针nullptr。
int *ptr new int; // 为指针分配内存
delete ptr; // 释放指针所指向的内存
//此时 ptr 成为野指针因为它仍然指向已经被释放的内存
ptr nullptr; // 避免野指针应该将指针置为 nullptr 或赋予新的有效地址避免返回局部变量的指针。注意函数参数的⽣命周期 避免在函数内释放调⽤⽅传递的指针
void foo(int* ptr) { // 操作 ptr delete ptr; // 这⾥可能造成调⽤⽅的指针成为野指针 ptr nullptr;
}
int main() { int* ptr new int; foo(ptr);
}使用智能指针使用C11引入的智能指针如std::unique_ptr、std::shared_ptr等它们可以自动管理内存生命周期避免了手动管理内存带来的潜在问题从而减少了野指针的风险。
野指针和悬浮指针
区别在于野指针可能指向任意未知或无效的内存地址而悬空指针则是指向已经被释放或者超出作用域的对象的地址。悬空指针通常是由于对已释放对象的指针未及时置空而产生的而野指针则可能是由于未初始化、错误释放或者错误使用指针而产生的。虽然两者都可能导致程序出错但野指针的来源更加广泛也更容易产生严重的后果。 以下为悬空指针的典型案例
int *ptr;
{int value 10;ptr value; // 指针指向局部变量value当value超出作用域后ptr就成为悬空指针
} // value超出作用域指针ptr成为悬空指针内存对齐
什么是内存对其
元素是按照定义顺序一个一个放到内存中去的但并不是紧密排列的。从结构体存储的首地址开始每个元素放置到内存中时它都会认为内存是按照自己的大小通常它为4或8来划分的因此元素放置的位置一定会在自己宽度的整数倍上开始这就是所谓的内存对齐。
为什么要内存对齐
引用的一位B友(L__B_)的评论 一般来说64位机器对应8个字也就是每次取八个字节而且由于内存的分层级策略直接和CPU打交道的是CPUcache而一个cacheline一般是32或64个字节。完全不对齐的话CPU读取一个数据的寻址次数将大大增加甚至有些CPU如果你不照着8字节或者4字节对齐直接g对齐的话能够保证更少的cache miss加快CPU处理速度。
内存对其的规则
仍然来自B友(L__B_)的评论 64位系统对应8字节为了减少存取次数数据成员应该以8字节为单位存取保证中途不会跨越式的拿到其他不完整的成员数据比如int char int从头到尾依次字节数为4 1 4那么八个字节取出发现会拿到第三个成员的不完整数据所以我们给第二个成员padding到4字节所以总共这个结构体就是12字节。同样我们假设上述的结构体类型为t那么有下列结构 int64_t int64_t t int64_t int64_t8 8 12 8 8。以8字节遍历发现在第四次遍历的时候拿到了其他成员的数据所以给这12这个结构padding到16所以总共48字节。32位默认4字节也是同理。