项目源代码:高并发内存池
1.调试代码及分析
#include"ConcurrentAlloc.h"
#include"ObjectPool.h"
#include"Common.h"
void BenchmarkMalloc(size_t ntimes, size_t nworks, size_t rounds)
{
std::vector<std::thread> vthread(nworks);
std::atomic<size_t> malloc_costtime(0);
std::atomic<size_t> free_costtime(0);
for (size_t k = 0; k < nworks; ++k)
{
vthread[k] = std::thread([&, k]() {
std::vector<void*> v;
v.reserve(ntimes);
for (size_t j = 0; j < rounds; ++j)
{
size_t begin1 = clock();
for (size_t i = 0; i < ntimes; i++)
{
//v.push_back(malloc(16));
v.push_back(malloc((16 + i) % 8192 + 1));
}
size_t end1 = clock();
size_t begin2 = clock();
for (size_t i = 0; i < ntimes; i++)
{
free(v[i]);
}
size_t end2 = clock();
v.clear();
malloc_costtime += (end1 - begin1);
free_costtime += (end2 - begin2);
}
});
}
for (auto& t : vthread)
{
t.join();
}
printf("%u个线程并发执行%u轮次,每轮次malloc %u次: 花费:%u ms\n",
nworks, rounds, ntimes, malloc_costtime.load());
printf("%u个线程并发执行%u轮次,每轮次free %u次: 花费:%u ms\n",
nworks, rounds, ntimes, free_costtime.load());
printf("%u个线程并发malloc&free %u次,总计花费:%u ms\n",
nworks, nworks * rounds * ntimes, malloc_costtime.load() + free_costtime.load());
}
// 单轮次申请释放次数 线程数 轮次
void BenchmarkConcurrentMalloc(size_t ntimes, size_t nworks, size_t rounds)
{
std::vector<std::thread> vthread(nworks);
std::atomic<size_t> malloc_costtime(0);
std::atomic<size_t> free_costtime (0);
for (size_t k = 0; k < nworks; ++k)
{
vthread[k] = std::thread([&]() {
std::vector<void*> v;
v.reserve(ntimes);
for (size_t j = 0; j < rounds; ++j)
{
size_t begin1 = clock();
for (size_t i = 0; i < ntimes; i++)
{
//v.push_back(ConcurrentAlloc(16));
v.push_back(ConcurrentAlloc((16 + i) % 8192 + 1));
}
size_t end1 = clock();
size_t begin2 = clock();
for (size_t i = 0; i < ntimes; i++)
{
ConcurrentFree(v[i]);
}
size_t end2 = clock();
v.clear();
malloc_costtime += (end1 - begin1);
free_costtime += (end2 - begin2);
}
});
}
for (auto& t : vthread)
{
t.join();
}
printf("%u个线程并发执行%u轮次,每轮次concurrent alloc %u次: 花费:%u ms\n",
nworks, rounds, ntimes, malloc_costtime.load());
printf("%u个线程并发执行%u轮次,每轮次concurrent dealloc %u次: 花费:%u ms\n",
nworks, rounds, ntimes, free_costtime.load());
printf("%u个线程并发concurrent alloc&dealloc %u次,总计花费:%u ms\n",
nworks, nworks * rounds * ntimes, malloc_costtime.load() + free_costtime.load());
}
int main()
{
size_t n = 10000;
cout << "==========================================================" << endl;
BenchmarkConcurrentMalloc(n, 4, 10);
cout << endl << endl;
BenchmarkMalloc(n, 4, 10);
cout << "==========================================================" << endl;
return 0;
}
创建了4个进程,每个进程执行10轮次,每次申请释放1w次,分析自己实现的内存池和系统提供的malloc、free之间的性能差距。
- 运行结果:
1.2VS下性能工具分析
链接: VS性能分析工具介绍
2.复杂问题的调试技巧
2.1调用堆栈
在打了断点情况下去调试,可以调出函数的调用堆栈,通过调用堆栈可以查看函数的前后调用关系。
可以看看这篇博客: C语言–调用堆栈及栈区内存使用
2.2条件断点
条件断点是一种在代码调试过程中使用的调试工具,它允许在满足特定条件时中断程序的执行,而不仅仅是在达到特定代码行时中断。条件断点对于帮助程序员诊断和解决问题非常有用,特别是在复杂的应用程序中。
以下是条件断点的一些关键特点和用途:
中断条件:条件断点允许您指定一个中断触发的条件。这通常是一个布尔表达式,当该表达式的值为真时,程序执行会中断。例如, 可以在循环中设置条件断点,以便在循环的第10次迭代时中断。
条件断点的位置:条件断点可以设置在代码的特定行或特定函数的入口处。它可以帮助 精确定位需要调试的代码部分。
日志和操作:一些调试工具允许 在条件断点触发时记录日志或执行自定义操作。这对于收集调试信息或执行特定操作以诊断问题非常有用。
计数条件断点: 还可以设置条件断点以在满足特定条件的情况下中断,例如当某个计数器达到指定值时。这对于跟踪迭代或事件发生次数非常有用。
临时条件断点:一些调试器允许您设置临时条件断点,这意味着它们只会在一次触发后自动删除,而不会影响以后的执行。
忽略计数: 可以设置条件断点,使其在满足条件时连续中断多次,或者在满足条件后中断一次后自动忽略后续的满足条件。
条件断点在以下情况下非常有用:
当 希望在特定情况下中断程序执行,例如找到数组中的特定值或在某个变量达到特定值时。
当 希望追踪特定事件的发生次数,以便诊断问题或优化性能。
当 需要记录某些状态或信息以帮助调试。
使用条件断点可以显著提高调试的效率,因为它允许 仅在特定条件下中断程序,而不是每次执行都中断。这有助于减少调试的干扰,同时更快地解决问题。不同的集成开发环境(IDE)和调试器提供条件断点的不同实现方式,但通常都有类似的功能。
- 实例
当使用条件断点时, 可以设置中断条件来根据特定的条件来触发断点。这是一个示例,演示如何在C++中使用条件断点来中断程序的执行:
假设 有一个简单的C++程序,它计算斐波那契数列,并且 想要在计算到第n个斐波那契数时中断程序的执行。
#include <iostream>
int Fibonacci(int n) {
if (n <= 1) {
return n;
}
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
int main() {
int n = 10; // 设置要计算的斐波那契数的位置
int result = Fibonacci(n);
std::cout << "Fibonacci(" << n << ") = " << result << std::endl;
return 0;
}
现在,假设 希望在计算到第5个斐波那契数时中断程序的执行。使用条件断点, 可以执行以下步骤:
在 的集成开发环境(IDE)中,打开源文件,并找到Fibonacci函数的调用,即 Fibonacci(n)。
在该行代码上设置条件断点。具体设置方法因IDE而异,但通常右键单击该行代码,选择 “添加条件断点” 或类似选项。
在条件断点设置对话框中,输入中断条件,例如 n == 5。这将使程序在 n 的值等于5时中断。
运行程序。当程序执行到第5个斐波那契数的计算时,它将中断执行,让 检查程序状态和调试问题。
这就是一个简单的例子,演示如何使用条件断点来在满足特定条件时中断程序的执行。 可以根据 的需要定义更复杂的中断条件,以帮助诊断和解决问题。条件断点是调试复杂应用程序时的强大工具,因为它们可以帮助 仅在特定情况下中断程序,而不是每次执行都中断。
调试技巧相关博客:
链接: VS断点调试技巧
本篇博客就介绍到这,创作不易点赞支持~