malloc / new

malloc 不会自动调用构造函数,通过绕过构造函数和析构函数,直接用底层手段手动控制对象的生命周期,避免额外的函数调用开销。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Person {
public:
int age;
float height;
Person();
};
Person::Person(void){
std::cout << "调用构造函数" << std::endl;
}
Person::~Person(void){
std::cout << "调用析构函数" << std::endl;
}

Person* p = (Person*)malloc(sizeof(Person));
std::cout << "1" << std::endl;
p->age = 25;
p->height = 175.5f;
free(p);
std::cout << "2" << std::endl;

auto t = new Person();
std::cout << "1" << std::endl;
delete(t);
1
2
调用构造函数
1
调用析构函数

移动构造 / 拷贝构造

移动构造 仅接管指针(原对象置空)

ClassName(ClassName &&obj)
{this.data = obj.data; obj.data = nullptr}

拷贝构造 深拷贝,分配新内存(复制),性能差

ClassName(const ClassName &obj)
{this.data = new int(*obj.data)}

emplace_back() / push_back()

push_back() 先创建元素,再将这个元素拷贝或者移动到容器中,性能差。
emplace_back() 直接在容器尾部创建元素,无拷贝或移动元素的过程。


深拷贝 / 浅拷贝

浅拷贝 拷贝指针地址,共享资源。
深拷贝 拷贝资源内容,各自拥有自己的资源,性能差。


堆 / 栈

  • 字符串拼接,string(堆) / char(栈)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    #include <benchmark/benchmark.h>
    #include <string>
    // 测试用例:N次字符串拼接
    #define N 1000
    // 方法1:std::string
    void funcString(benchmark::State& state){
    for (auto _ : state){
    std::string s;
    for(int i=0; i<N; ++i) s += "a"; // SSO优化初期,后期堆分配
    benchmark::DoNotOptimize(s);
    }
    }
    BENCHMARK(funcString);
    // 方法2:char[](栈)
    void funcCharstack(benchmark::State& state){
    for (auto _ : state){
    char arr[N]; // 危险!可能栈溢出
    for(int i=0; i<N; ++i) arr[i] = 'a';
    benchmark::DoNotOptimize(arr);
    }
    }
    BENCHMARK(funcCharstack);
    // 方法3:char*(堆)
    void funcCharheap(benchmark::State& state){
    for (auto _ : state){
    char* ptr = new char[N];
    for(int i=0; i<N; ++i) ptr[i] = 'a';
    benchmark::DoNotOptimize(ptr);
    delete[] ptr;
    }
    }
    BENCHMARK(funcCharheap);
    // 方法4:std::vector<char>
    void funcVectorChar(benchmark::State& state) {
    for (auto _ : state) {
    std::vector<char> vec;
    vec.reserve(N); // 提前分配堆空间,避免多次扩容,提升性能
    for (int i = 0; i < N; ++i) vec.emplace_back('a');
    benchmark::DoNotOptimize(vec);
    }
    }
    BENCHMARK(funcVectorChar);
    运行耗时对比
    性能测试网站
    显然耗时 stringvector<char> > char* > char[]
    另外 vector 在未提前 reserve() 空间的情况下,性能基本与 string 相同,提前分配堆空间后提升了约10%的速度。

多线程

lock_guard / unique_lock

lock_guard 仅自动加解锁。
unique_lock 可手动加解锁,支持延迟锁定,可用条件变量 condition_variable ,性能差。

atomic / std::mutex

std::atomic 底层用 CPU 指令,适合单个变量。
std::mutex 适合多个变量同步,性能差。


内存池

  1. 减少频繁调用系统级内存分配函数(如 malloc/new)的开销
    系统分配一次内存(尤其是小块)会涉及锁、页表管理、对齐等,代价很高。
    内存池一次性向系统申请一大块内存,再在池内划分出小块供程序使用。

  2. 加快内存分配速度
    池内的分配通常只是指针移动或从空闲链表取节点,非常快,几乎 O(1)。