首页/文章/ 详情

C++开发CFD代码需要注意的内存管理

1月前浏览1176

1、内存管理的重要性


     

   

在C++编程中,内存管理是核心概念之一。它直接影响到程序的执行效率。如果内存管理做得不好,即使C++作为一种编译型语言在理论上具有性能优势,实际运行时也可能比解释型语言更慢。幸运的是,掌握内存管理并不难,只需理解一些基础概念。C++语言本身不自动管理内存,而是将这一责任交给了开发者。不过,通过使用标准模板库(STL),我们可以在很大程度上简化内存管理的任务,从而专注于编写高性能的代码。


2、栈(Stack)与堆(Heap)


     

   

理解C++中的内存及其管理,可能是掌握这门语言的一半关键。栈是相对较小但速度快的内存区域,通常大小在8MB左右。堆则是一个可以非常大且速度稍慢的内存区域,理论上没有大小限制。

理解栈和堆的工作原理对于有效管理内存至关重要。栈是程序运行时用于存储局部变量的内存区域,其大小相对固定,通常在操作系统的控制下,容量有限但访问速度很快。堆则是一个动态的内存区域,其大小理论上没有限制,可以根据程序的需要动态分配和回收。栈的快速访问特性使其适合存储小的、生命周期短的变量,而堆则适合存储大的数据结构,如大型数组,因为这些数据可能在程序运行期间动态增长。


3、栈与堆的比喻


     

   

如果打个比喻,想想停车。可以将栈比作多层停车场,你有两个选择,要么你停在一个多层停车场,或者你使用代客泊车服务。如果你使用多层停车场,你知道你确切地停在哪里。你知道是哪一层,如果我们假设每个停车位都标记了,你也知道那一层上的位置。这意味着找到你的车很快。如果你使用代客泊车服务,你交出你的车,它会停在某个地方,但你不知道在哪里,你只知道一个数字或票据,你可以用它来取回你的车。所以你不知道车在哪里,但你有一种机制,通过它你可以取回你的车(比如出示你的票据)。我们可以同意,平均来说,使用多层停车场会比代客泊车更快地找到你的车。在这个比喻中,多层停车场是我们的栈,代客泊车服务是我们的堆。


4、使用栈和堆的时机


     

   

所以栈是一块小的内存区域,我们可以快速地从中检索数据,但我们在可用空间和可以存储的数据量上是有限的。另一方面,堆是广阔的,我们可以存储大量的数据。然而,如果我们想检索它,我们首先需要通过引用找到它,这需要更长的时间。

我们说栈很小,但这只是与堆相比,它仍然可以存储相当多的数据。通常,栈保存我们频繁访问的信息,在CFD的背景下,这些是我们的求解器设置,比如迭代次数、时间步长大小、CFL数等等。所以如果一个变量保存一个值(比如一个数字、一个字符串或一个布尔值),那么把它放在栈上,但如果变量保存同一类型的多个值,即一个数字、字符串、布尔值等的数组,那么它应该放在堆上。

在决定使用栈还是堆时,需要考虑数据的大小和生命周期。例如,在CFD模拟中,处理大量的坐标和解决方案数组时,由于它们的大小可能很大且在程序运行期间可能增长,因此应该在堆上分配。这样可以避免因数据量过大而导致栈溢出。相对地,对于那些仅存储单个值的变量,如整数、浮点数、布尔值或短字符串,由于它们占用的空间小,生命周期通常与函数调用相关,因此更适合存储在栈上。

对于大型数据数组,如坐标、速度、压力、温度等解决方案数组,应使用堆。这些数据可能增长,因此应放在堆上以避免栈溢出。其他所有内容则放在栈上。


5、内存缓存


     

   

CPU高速运行需要快速的数据访问,这通过内存缓存来实现。缓存是位于CPU和主内存之间的一层快速存储,它按照一定的层次结构(L1、L2、L3等)组织,以减少CPU访问主内存的次数。当CPU执行指令需要数据时,它会首先在缓存中查找,如果找到则称为缓存命中,访问速度非常快;如果未找到,则需要从更慢的存储介质中获取数据,这称为缓存未命中,会显著降低程序的执行速度。


CPU通过内存层次结构访问数据,包括寄存器、L1、L2、L3缓存,以及主内存和硬盘。缓存的大小与访问速度成反比。CFD应用需要高效管理内存,因为它们对内存的需求很大。

从理论上讲,你可以使用硬盘作为RAM。有了TB级的硬盘,这将是非常有利可图的。实际上,如果你使用的是像Ubuntu这样的UNIX发行版,在安装阶段它会询问你是否想要设置交换空间,这本质上是分配一部分硬盘用作RAM。如果你使用的是旧的固态硬盘,我们可以看到大约需要3毫秒才能访问数据。与62.9纳秒相比,你很快就会明白为什么你不想使用硬盘作为RAM。如果你使用硬盘作为RAM,你将增加你的计算时间大约48倍(3ms / 62.9 ns)。

那么,我们为什么要花这么多时间在CPU及其缓存上呢?因为CFD应用程序是内存密集型的应用程序,我们需要有效地管理它。


6、屋顶线内存模型(Roofline Memory Model)


     

   

大多数人可能不知道缓存,这没关系,但我们作为CFD开发者需要至少在基础知识上理解内存,现在你已经知道了。这里还有一个小秘密;大多数应用程序实际上是内存受限的,即如果你要测量你的应用程序的性能(通常以GFLOPS或(giga)每秒浮点操作数来完成,即你每秒能够做多少浮点操作),你将不会以CPU的最大时钟速度运行,而是受到你加载的内存量的限制。

屋顶线模型是一个用于评估和理解计算性能的工具,它揭示了程序性能与内存带宽之间的关系。根据这个模型,程序的性能受限于内存的带宽,即数据加载的速度。如果程序的计算强度(每字节执行的浮点操作数)足够高,就可以接近CPU的最大性能。反之,如果内存访问成为瓶颈,即使CPU的计算能力很强,程序的整体性能也会受到限制


在这个图表中,我们可以看到,只有在我们有足够的(浮点)操作数每秒(FLOPS)对于我们加载的每个字节时,我们才能获得峰值性能,换句话说,我们想要最大化FLOPS的数量,并最小化加载的内存量,实现这一点的一种方法是尽可能避免缓存未命中(但你不能完全避免缓存未命中,最终你必须将新数据加载到你的缓存中,你只是想在可能的地方最小化)


7、总结


     

   

这就是关于内存管理的全部内容,简单来说。虽然我们在这里只是浅尝辄止,您可以使任何主题变得更加复杂,但您现在应该对这个问题有了一个很好的了解。


    



来源:CFD饭圈
FluentCFX燃烧Polyflow理论控制ParaViewParticleWorks
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2024-09-08
最近编辑:1月前
CFD饭圈
硕士 分享CFD文章,感谢关注
获赞 22粉丝 21文章 376课程 0
点赞
收藏
作者推荐

【经典教材翻译】3-流体的理想气体、体变模量、蒸汽压力、表面张力和毛细力

1、理想气体定律 气体的压力、密度和温度通过一个状态方程相互关联。在空气的普通条件下,其中 P 是绝对压力,ρ 是密度,T 是绝对温度,R 是气体常数。上述方程称为理想气体定律或完美气体方程。遵守这个方程的气体称为理想气体。理想气体定律的气体常数 R 由给出,其中 ℝ 是称为通用气体常数,等于 8314 J/kg.K,M 是气体的摩尔质量。对于空气,气体常数 R = 286.9 J/kg.K。 2、体变模量,Ev 体变模量bulk modulus决定了流体的可压缩性。换句话说,它是流体在受到压力时密度变化的量度。它定义为 其中 dP 是为了使体积改变 dVi 所需的压力变化,Vi 是初始体积。负号表示压力的增加伴随着体积的减少。体变模量的量纲是 FL^-2;单位是 N/m^2。体变模量较高的值表明压缩流体很困难。例如,水的体变模量是 2.15 x 10^9 N/m^2,这意味着需要巨大的压力才能稍微改变水的体积。在所有实际目的中,水(和许多其他液体)被视为不可压缩的。 3、气体的体变模量 气体有一个将压力、密度和温度联系起来的状态方程。这使我们能够推导出压力和密度之间的显式关系。这样的关系取决于正在考虑的过程——等温(isothermal,在恒定温度下)或等熵(isentropic,在恒定熵下)。方程是和其中 k 是在恒定压力下特定的热容,Cp 与在恒定体积下的特定热容,Cv 的比率。另外 其中 R 是气体常数。在普通条件下,空气的 k = 1.4。通过将定义代入体变模量,Ev = P 对于等温过程Ev = kP 对于等熵过程因此,我们看到气体的体变模量取决于其压力。鉴于在标准温度和压力条件下,空气的大气压力为 1.01325 x 10^5 N/m^2,体变模量是同一量级,而水的为 2.15 x 10^9 N/m^2。这些数字表明,空气大约是水的 15,000 倍可压缩。 4、蒸汽压力 当液体暴露于大气中时,分子从其表面以蒸汽形式逸出。如果将液体置于封闭容器中,这种活动持续进行,以至于蒸汽填充了液体水平面和容器之间的空间。产生的压力达到平衡。蒸汽被认为已饱和。它对液体表面施加的压力是蒸汽压力。 5、表面张力,σ 表面张力作用于两种不相混合的液体之间或液体和气体之间,即水和空气之间。两种流体之间的界面假定像处于拉伸应力下的拉伸膜一样。这种应力是保持膜位置所需的。在日常生活中可以找到许多表面张力影响的例子。钢针会因水面上发展出的明显张力而浮在水上。水珠在光滑表面上形成。当汞倒在光滑表面上时,会形成微小的球形。在界面上作用于液体分子的未平衡的内聚力由表面张力产生的拉力平衡。表面张力,σ,表示为单位距离的力(N/m),量纲为 FL^-1。它的大小取决于接触的两种流体和温度。 6、液滴内的压力 正是由于表面张力,液滴内部的液体压力会增加。考虑下图所示的气泡的自由体图。如果边缘处的表面张力力与气泡内部的压力力平衡,我们有 即,其中 P 是液滴内部与外部之间的压力差。此外,液滴内部的压力大于外部的压力。 7、毛细管 如果将一个小开口管插入装有水的容器中,水会上升到管中。形成了一个液-气-固界面。在这种情况下,固体和水之间的吸附力或粘附力很强,能够克服液体分子之间的相互内聚力。这就是水上升到管中的原因。液体被认为润湿了表面。液体柱的高度与表面张力、管半径、液体的比重量和液体与管之间的接触角 θ 有关。由于表面张力产生的垂直力 2πRσcos(θ) 和流体的重量 γπR^2h,将彼此平衡。 或可以看出,如果管半径小,毛细上升 h 就会很明显。也就是说,管越窄,流体在其中上升的高度就越高。流体是否在毛细管中上升取决于上图所示的接触角 (θ)。这是固体和液体表面之间的角度。当这个角度小于 90° 时,表面张力就会把流体拉过管子。存在一个向上凹的液面(meniscus)。液体被认为润湿了表面。但是,当角度大于 90° 时,如与汞发生的情况一样,液位实际上被压低了,液体不润湿表面。 来源:CFD饭圈

未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习 福利任务 兑换礼品
下载APP
联系我们
帮助与反馈