不能足够快地分配内存?

时间:2016-03-05 14:21:25

标签: c++ memory memory-management

假设您的任务是解决应用程序中的性能瓶颈问题。通过分析,我们发现瓶颈与内存分配有关。我们发现,无论我们分配多少内存线程,应用程序每秒只能执行N个内存分配。为什么我们会看到这种行为,以及我们如何提高应用程序分配内存的速率。 (假设我们不能改变我们分配的内存块的大小。假设我们不能减少动态分配内存的使用。)

4 个答案:

答案 0 :(得分:2)

好的,存在一些解决方案 - 但几乎所有似乎都要通过某种约束或其他约束来排除。

1.让更多线程分配内存

  

我们发现,无论我们分配多少内存线程,应用程序每秒只能执行N次内存分配。

由此,我们可以交叉任何关于添加更多线程的想法(因为“无论有多少线程”......)。

2.一次分配更多内存

  

假设我们无法更改正在分配的内存块的大小。

显然,我们必须分配相同的块大小。

3.使用(某些)静态内存

  

假设我们无法减少动态分配内存的使用。

这个我觉得最有趣的一点。提醒我一个关于FORTRAN程序员的故事(在Fortran进行动态内存分配之前),刚刚使用堆栈上分配的巨大静态数组作为私人堆。 不幸的是,这种约束使我们无法使用这样的技巧。但是,它确实可以解决这个问题的一个方面。

我的解决方案

在执行开始时(程序中的任一个或基于每个线程)进行多次 ^ 内存分配系统调用。然后在程序中使用稍后的内存(以及现有的动态内存分配)。

* 注意:“几个”可能是一个确切的数字,由分析确定,问题在开头提到< / em>的

TL; DR

技巧是修改内存分配的时间

答案 1 :(得分:0)

  

...应用程序每秒只能执行N次内存分配,   无论我们有多少线程分配内存。我们为什么会这样   看到这种行为,我们如何提高这种行为的速度   应用程序可以分配内存。

恕我直言,最可能的原因是分配来自一个共同的系统池。

因为它们共享一个池,所以每个线程必须通过一些关键部分阻塞机制(可能是一个信号量)获得访问权限。

竞争动态内存的线程越多(即使用new)将导致更多关键部分阻塞。

任务之间的上下文切换是浪费时间。

如何提高费率?

选项1 - 序列化使用...当然,这意味着您不能简单地尝试在另一个级别使用信号量。对于我工作的一个系统,在系统启动期间发生了高动态内存利用率。在这种情况下,最简单的方法是更改​​启动,使线程n + 1(此集合)仅在线程n完成初始化并进入等待输入循环后才开始。只有一个线程一次启动它,(并且很少有其他动态内存用户在运行)没有发生关键部分阻塞。 4个同步启动需要30秒。 4个序列化的初创公司在5秒内完成。

选项2 - 为每个特定线程提供ram池和私有new / delete。如果一次只有一个线程访问池,则不需要临界区或信号量。在嵌入式系统中,这里的挑战是为线程分配合理数量的私有池而不是浪费太多。在具有数GB RAM的桌面上,这可能不是一个问题。

答案 2 :(得分:0)

看起来像一个具有挑战性的问题,虽然没有细节,但你只能做一些猜测。 (这很可能就是这个问题的想法)

此处的限制是分配数量,而不是分配的大小。 如果我们可以假设您可以控制分配的位置,则可以一次为多个实例分配内存。请将以下代码视为伪代码,因为它仅用于说明目的。

const static size_t NR_COMBINED_ALLOCATIONS = 16;
auto memoryBuffer = malloc(size_of(MyClass)*NR_COMBINED_ALLOCATIONS);
size_t nextIndex = 0;
// Some looping code
    auto myNewClass = new(memoryBuffer[nextIndex++]) MyClass;
    // Some code
    myNewClass->~MyClass();
free(memoryBuffer);

您的代码很可能变得更加复杂,尽管您很可能会解决这个瓶颈问题。如果你必须返回这个新类,你甚至需要更多的代码才能进行内存管理。

根据这些信息,您可以为自己的STL编写自己的分配器实现,覆盖“&#39; new&#39;并且&#39;删除&#39;经营者......

如果这还不够,请尝试挑战限制。为什么你只能进行固定数量的分配,这是因为独特的锁定?如果是这样,我们可以改善吗?为什么需要那么多的分配,改变正在使用的算法来解决这个问题......

答案 3 :(得分:0)

我相信你可以使用一个可以负责内存分配的独立线程。该线程将具有包含线程标识符映射和所需内存分配的队列。线程不会直接分配内存,而是向队列发送分配请求并进入等待状态。该队列将尝试从队列中处理每个请求的内存分配并唤醒相应的休眠线程。当负责内存处理的线程由于限制而无法处理分配时,它应该等到可以再次分配内存。

可以在解决方案中构建另一层,因为@ Tersosauros的解决方案建议稍微优化速度,但它应该基于类似上面的想法。