一、new 和 malloc 的区别
| 特性 | new / delete (C++) | malloc / free (C) |
|---|---|---|
| 语言 | C++ 运算符 | C 标准库函数 |
| 返回类型 | 返回具体类型指针 | 返回 void*,需要强制转换 |
| 分配大小 | 自动计算类型大小 | 需要手动计算字节数 |
| 构造函数 | 调用构造函数 | 不调用构造函数 |
| 析构函数 | 调用析构函数 | 不调用析构函数 |
| 内存不足 | 抛出 std::bad_alloc 异常 |
返回 NULL |
| 重载 | 可以重载 operator new |
不能重载 |
| 初始化 | 可以初始化(如 new int(5)) |
不进行初始化 |
| 数组 | 支持 new[] 和 delete[] |
需要手动计算数组大小 |
| 类型安全 | 类型安全 | 类型不安全 |
| 使用示例 | int* p = new int(10); |
int* p = (int*)malloc(sizeof(int)); |
| 释放 | delete p; / delete[] arr; |
free(p); |
二、calloc 和 malloc 的区别
| 特性 | calloc | malloc |
|---|---|---|
| 函数原型 | void* calloc(size_t num, size_t size); |
void* malloc(size_t size); |
| 参数 | 两个参数:元素个数和每个元素大小 | 一个参数:总字节数 |
| 初始化 | 自动初始化为0 | 不初始化(内容随机) |
| 内存计算 | 自动计算总大小:num * size |
需要手动计算总大小 |
| 性能 | 稍慢(因为要初始化) | 稍快(不初始化) |
| 使用场景 | 需要零初始化的数组或结构体 | 不需要初始化或后续会覆盖的情况 |
三、在1G内存的计算机中能否malloc(1.2G)?为什么?
实际安装在计算机中的RAM内存(1GB)。操作系统为每个进程提供的虚拟地址空间(通常很大,如32位系统4GB,64位系统更大),地址空间布局为
32位进程的典型地址空间布局(4GB):
┌─────────────────┐ 0xFFFFFFFF
│ 内核空间 │ (1GB或2GB)
├─────────────────┤
│ │
│ 栈(stack) │ ← 向下增长
├─────────────────┤
│ ... │
├─────────────────┤
│ 堆(heap) │ ← 向上增长
├─────────────────┤
│ BSS段(.bss) │ 未初始化全局变量
├─────────────────┤
│ 数据段(.data) │ 已初始化全局变量
├─────────────────┤
│ 代码段(.text) │ 程序代码
└─────────────────┘ 0x00000000
Linux允许分配超过物理内存+交换空间的内存。
由于交换空间(Swap Space),当物理内存不足时,操作系统会将一些不常用的物理页面移动到磁盘上的交换空间,从而腾出物理内存给需要的页面。当程序再次访问被换出的页面时,操作系统会将其从磁盘换入物理内存(可能需要换出其他页面)。因此,1.2G的虚拟内存中,只有一部分(最近被访问的)放在物理内存中,其余部分可能放在交换空间中。所以理论上可以分配。
# Linux查看交换空间
$ free -h
total used free shared buff/cache available
Mem: 7.7G 2.3G 3.9G 200M 1.5G 4.9G
Swap: 2.0G 0B 2.0G # ← 交换空间
# Windows页面文件
# 在C:\pagefile.sys(隐藏系统文件)
调用malloc(1.2G)可能成功返回非NULL指针,但实际使用这些内存时可能会导致系统交换或程序崩溃。真正的限制是虚拟地址空间大小和交换空间大小,而不仅仅是物理内存大小。