个人Linux C++问题汇总

  1. 避免使用vector<bool>,尽量使用bitset或者deque<bool>

    因为vector<bool>不是容器,底层是bool值按bit存储

  2. STL list容器数据结构上看是带空头的双向循环链表

  3. 容器迭代器要注意迭代器失效问题,insert/erase后要及时更新迭代器

  4. auto_ptr不能管理数组对象、自定义对象;应该使用C++11中的智能指针加自定义删除器

    unique_ptr<char, function<void(char*)>> sp(new char[100], 
    	[](char *p)->void {    // 返回值为空,可省略
    		delete []p;
    	}	
    );
    
    auto deletor = [](char* p){delete[] p;};
    unique_ptr<char, decltype(deletor)>> sp(new char[100], deletor);
    
    // make_unique 不支持自定义删除器
    
  5. 为什么 C++ 有了函数指针还要引入std::function?

    函数指针指向的是代码段中的一段代码,不具备捕捉上下文的能力,当一个回调传入需要模块A中定义的函数和模块B的运行产生的数据一起传递给C模块来调用时,单纯的函数指针不够用。

  6. C++ 11: push/insert --> emplace | push_front ---> emplace_front | push_back ---> emplace_back

    1. 增加移动构造函数 Test(Test &&t) 复用产生的临时对象t,以提高效率
  7. C++ 17: std::map 提供了 try_emplace 方法和 insert_or_assign 方法

    1. try_emplace 方法: 该方法会检测指定的key是否存在,如果存在,则什么也不做。
    2. insert_or_assign 方法:map中指定的 key不存在则插入相应的 value,存在则更新其value。
  8. 实现了移动构造函数或移动赋值运算符的类对象才支持std::move()

  9. Move Constructor & Move operator=

    template<typename T, typename Deletor>
    class unique_ptr
    {
    public:
    	// Move Constructor
    	unique_ptr(unique_ptr&& rhs)
    	{
    		this->m_pT = rhs.m_pT;
    		rhs.m_pT = nullptr;
    	}
    
    	// Move  operator=
    	unique_ptr& operator=(unique_ptr&& rhs)
    	{
    		this->m_pT = rhs.m_pT;
    		rhs.m_pT = nullptr;
    		return *this;
    	}
    };
    
  10. goto label 到 label之间不能存在变量声明

  11. 不要频繁调用printf()

最近遇见调用一个库里函数会打印2条信息,循环调用1w次,总时间达到90秒左右,和单次调用的时间开销天壤之别;函数调用前后计时,大部分情况是40+us,隔一段时间出现350+ms,让负责维护库的同学去掉打印后,调用1w次总时间150ms.

  • 频繁输出信息时,最好一次性输出,避免频繁调用 printf()
  • 当需要立即将缓冲区中的数据输出时,可以显式地调用 fflush(stdout),强制刷新缓冲区;
  • 对于频繁需要输出大量信息的情况,也可以使用系统调用 write() 来代替 printf()。
  • 使用 printf() 打印消息并带有 '\n'(换行符)可以让缓冲区立即刷新, 但使用 printf() 打印消息并不一定会实时刷新缓冲区,因为缓冲区的刷新时间受到多种因素的影响,例如硬件设备、是否输出到终端、缓冲区大小等等。
  1. 函数内部占内存较大的变量不要定义为局部变量

嵌入式设备的配置模块,一个函数中定义了一个占内存1M的局部变量,用来备份数据。在子函数init()的子函数getXCode()时程序异常结束运行,addr2line只能看到结束在getXCode()
注释掉getXCode(),又报在下一个子函数出错,推测函数压栈时出了问题,走读代码,尝试修改时发现问题原因
解决:堆或者定义为静态变量每次使用时memset

13.top输出中各字段详解

在计算机科学中,"top" 是一个常用的命令行工具,用于显示系统中运行的进程的实时信息。下面是 "top" 输出中各字段的详细解释:

  1. PID(Process ID):进程的唯一标识符。每个运行的进程都有一个独特的PID。
  2. USER(Username):启动该进程的用户名。
  3. PR(Priority):进程的优先级。较低的数值表示较高的优先级。
  4. NI(Nice Value):进程的优先级调整值。负值表示较高的优先级,正值表示较低的优先级。
  5. VIRT(Virtual Memory):进程使用的虚拟内存量,包括代码、库、数据等。
  6. RES(Resident Memory):进程当前使用的物理内存量。
  7. SHR(Shared Memory):进程使用的共享内存量。
  8. S(Status):进程的状态,常见的状态有:
    • R:运行(Running)R:运行(运行)
    • S:睡眠(Sleeping)S:睡眠(Sleeping)
    • D:不可中断的睡眠状态(Uninterruptible sleep)
    • Z:僵尸进程(Zombie)
    • T:停止(Stopped)T:停止(Stopped)
  9. %CPU(CPU Usage):进程在最近一次更新期间使用的CPU资源百分比。
  10. %MEM(Memory Usage):进程使用的物理内存占总内存的百分比。
  11. TIME+(CPU Time):进程已经使用的CPU时间总量。
  12. COMMAND(Command Name):启动进程的命令或程序名称。

这些字段提供了关于系统中运行的进程的重要信息,帮助用户了解进程的资源消耗情况、优先级以及当前状态,从而进行系统性能监测和调优。

14.top进程的各个状态对应的可能原因

以下是常见的进程状态及其可能的原因:

  1. R(Running):进程正在运行或准备运行。可能原因包括:
    • 进程正在执行其主要任务。
    • 进程正在等待系统资源(如CPU时间片、I/O等)。
  2. S(Sleeping):进程处于睡眠状态,等待某些事件的发生。可能原因包括:
    • 进程在等待某个事件的发生,如I/O操作的完成、信号的到达等。
    • 进程被阻塞,等待某个条件的满足。
  3. D(Uninterruptible sleep):进程处于不可中断的睡眠状态,通常发生在与硬件设备交互时。可能原因包括:
    • 进程正在等待硬件设备的响应,无法被中断。
    • 进程在等待某些硬件资源的释放。
  4. Z(Zombie):僵尸进程,进程已经终止,但是其父进程尚未对其进行资源清理。可能原因包括:
    • 父进程没有正确处理子进程的退出状态。
    • 父进程已经终止,无法进行清理操作。
  5. T(Stopped):进程处于停止状态,可能是由于收到了停止信号。可能原因包括:
    • 进程收到了停止信号,如SIGSTOP或SIGTSTP。
    • 进程在调试过程中被暂停。

这些是常见的进程状态及其可能的原因。进程的状态会根据不同的情况和系统环境发生变化。通过观察进程的状态,可以帮助诊断进程的运行情况,如是否正常运行、是否等待某些事件、是否发生了异常等。

15.top输出中vsz %vsz stack rss dirty 分别是什么意思

在 "top" 命令的输出中,以下字段表示:

  1. VSZ(Virtual Set Size):进程使用的虚拟内存大小(以KB为单位)。它包括进程的代码、数据、堆、共享库以及映射的文件等。
  2. %VSZ(Virtual Set Size的百分比):进程使用的虚拟内存大小占系统总虚拟内存的百分比。
  3. Stack(栈大小):进程使用的栈空间大小(以KB为单位)。栈用于存储局部变量、函数调用等。
  4. RSS(Resident Set Size):进程当前使用的物理内存大小(以KB为单位)。它表示实际驻留在物理内存中的部分,包括进程的代码、数据和堆。
  5. Dirty(脏页):进程所占用的内存中已经被修改但尚未写回到磁盘的部分(以KB为单位)。脏页是指进程对内存中的数据进行了修改,但尚未同步到磁盘。

这些字段提供了关于进程内存使用情况的信息。VSZ表示进程使用的虚拟内存大小,而RSS表示实际使用的物理内存大小。%VSZ表示进程虚拟内存大小在系统总虚拟内存中的比例。Stack字段显示进程使用的栈空间大小。Dirty字段表示进程所占用的内存中被修改但尚未写回磁盘的部分。

这些字段可以帮助您了解进程的内存占用情况,判断进程的内存使用情况是否合理以及是否存在内存泄漏等问题。

  1. new 失败直接抛出bad_alloc异常,不返回 null 。若不处理异常,应当用 new(std::nothrow) 代替new

  2. malloc_stats 打印 glibc 分配内存信息。


void print_mem_info(const char* s) {
    printf("------------------------\n");
    printf("-- %s\n", s);
    printf("------------------------\n");
    malloc_stats();
}

int main(int argc, char** argv) {
  
    int cnt = atoi(argv[1]);
    std::list<char*> free_list;

    print_mem_info("begin");

    for (int i = 0; i < cnt; i++) {
        char* m = new char[1024 * 64];
        memset(m, 'a', 1024 * 64);
        free_list.push_back(m);
    }

    print_mem_info("alloc blocks");

    for (auto& v : free_list) {
        delete[] v;
    }

    print_mem_info("free blocks");

    free_list.clear();
    print_mem_info("clear list.");

}

posted @   仓隽  阅读(112)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示