基于TI-RTOS的CC2650DK开发(19)---Stacks(栈)和Heap(堆)

7.5 Stacks(栈)
SYS/BIOS为硬件中断使用单个系统栈而为每个Task实例分配一个task栈。

7.5.1 系统栈
你可以配置系统栈的尺寸,它用于硬件中断和软件中断(如果Task不可用则用于Idle函数)。你可将系统栈尺寸设置为满足应用程序所需。见3.5.3节获取更多有关系统栈尺寸需求的信息。你可使用.stack片来控制系统栈位置。例如,下列配置声明将一个尺寸为0x400的系统栈放置于IRAM段内。
Program.stack = 0x400;
Program.sectMap[ ".stack"] =  "IRAM";
设置Program.stack在链接命令文件生成合适的链接选项,以在链接时允许系统栈的分配。例如,C6000应用程序的链接命令文件可包含命令选项  -stack 0x0400

查找项目的自动生成链接命令文件获取系统栈尺寸和位置相关的符号。C6000的是__TI_STACK_END和 __STACK_SIZE。

7.5.2 Task栈
如果Task模块可用,SYS/BIOS为应用程序所包含的每个Task实例(包含一个Idle线程的task栈)创建一个额外的栈。参考3.6.3节获取有关task栈尺寸需求信息。

你可以在配置文件中指定Task栈的尺寸。(你可以使用XGCONF来做这件事或直接编辑.cfg文件)如:
var Task = xdc.useModule( 'ti.sysbios.knl.Task');
/* Set default stack size for tasks */
Task.defaultStackSize =  1024;
/* Set size of idle task stack */
Task.idleTaskStackSize =  1024;
/* Create a Task Instance and set stack size */
var tskParams =  new Task.Params;
tskParams.stackSize =  1024;
var task0 = Task.create( '&task0Fxn', tskParams);

配置创建的Tasks可使用Program.sectMap[]来控制task栈,如:
/* Place idle task stack section */
Program.sectMap[ ".idleTaskStackSection"] =  "IRAM";
/* Place other static task stacks */
Program.sectMap[ ".taskStackSection"] =  "IRAM";

7.5.3 系统栈和任务栈的ROV
在运行时,你可以在CCS使用Tools > RTOS Object View (ROV)来获取每个Task实例的详细信息。了解ROV信息,请参考wiki页 http://rtsc.eclipse.org/docs-tip/RTSC_Object_ViewerDetailed标签显示了task栈的信息和状态。
基于TI-RTOS的CC2650DK开发(18)---Stacks(栈) - 阿巴睇 - 阿巴睇的博客

Module标签显示HwiStack(系统栈)的信息和状态。
基于TI-RTOS的CC2650DK开发(18)---Stacks(栈) - 阿巴睇 - 阿巴睇的博客
 
7.6 缓存配置
在SYS/BIOS 6.x中的C6000缓存尺寸由你所选择的平台决定。更改缓存尺寸,使用平台向导创建或修改平台。如7.2.2.2所描述。以下小节描述在SYS/BIOS中使用指定系列缓存模块以控制缓存行为。

7.6.1 在启动时配置缓存尺寸寄存器
对于C6000目标来说,可用ti.sysbios.hal.Cache模块从平台获取缓存尺寸,并在启动时设置缓存尺寸寄存器。ti.sysbios.hal.Cache模块是一个通用模块,它由指定系列所提供的 ti.sysbios.family.*.缓存模块来实现。见8.4节获取更多有关缓存模块和它的实现的相关信息。

例如在DA830中,缓存模块在启动时设置L1PCFG、L1DCFG和L2CFG寄存器。

7.6.2 通过配置参数来设置MAR寄存器
对于C6000目标来说, ti.sysbios.family.c64p.Cache模块定义了Cache.MAR##-##配置参数,使得你可以控制哪个外部存储地址是可缓存或不可缓存的。例如,Cache_MAR128_159就是这样一个配置参数。这些配置参数直接映射到设备上的MAR寄存器。每16M外部存储地址空间由一个MAR bit控制(0:不可缓存,1:可缓存)。

SYS/BIOS缓存模块拥有module-wide配置参数来映射到MAR寄存器。

默认情况下,C64P缓存模块通过设置所有相应的MAR bits为0x01让平台内定义的所有内存区域都为可缓存的。将DA830设备的外部内存范围从8000 0000h到80FF FFFFh为不可缓存,你可设置Cache.MAR128_159 = 0x0如下,这将MAR128寄存器设置为0。
var Cache = xdc.useModule( 'ti.sysbios.family.c64p.Cache');
Cache.MAR_128_159 = 0x0;
在为外部存储器空间设置MAR bit后,新的CPU访问地址将被缓存至L2 cache,或者L2不可用时,缓存到L1。请参考指定设备的MAR寄存器参考指南和它们对外部存储器地址的映射。

在系统启动时,缓存模块写入MAR寄存器并配置它们。

7.6.3 缓存运行时APIs
对任何拥有缓冲的目标来说,ti.sysbios.hal.Cache模块提供了APIs在运行时操作缓存。包括Cache_enable()、Cache_disable()、Cache_wb()和Cache_inv()。详见8.4.1。

7.7 动态内存分配
“Heap”是实现IHeap接口的模块。Heaps(堆)是动态内存管理器:它管理指定内存片并支持内存中片(“块”)的分配和释放。

内存分配尺寸由内存的“Minimum Addressable Units”(MAUs最小地址单元)丈量。MAU是可被CPU读写的数据存储的最小单位。对于C28x,它是16bit字。对于所有其它当前支持的目标系列,包括C6000、ARM和MSP430来说,是8bit字节。

7.7.1 内存策略
你可以全局或每个模块的基础上通过设置内存策略来减少应用程序的代码空间。当目标代码内存有着明显约束时,这尤其有用。
这些选项包括:
  • DELETE_POLICY:这是默认值。应用程序在运行时创建和删除对象(或此模块的对象)。需要将MODULE_create()函数和MODULE_delete()函数都对应用程序设为可用。
  • CREATE_POLICY:应用程序在运行时创建对象(或此模块的对象)。它不在运行时删除对象。需要将MODULE_create()函数对应用程序设为可用,但不需要MODULE_delete()函数。
  • STATIC_POLICY:应用程序在配置文件中创建所有对象(或所有此模块的对象)。不需要将MODULE_create()函数或MODULE_delete()函数对应用程序设为可用。

例如,以下配置声明设置所有模块默认内存策略为仅用静态实例创建:
var Defaults = xdc.useModule( 'xdc.runtime.Defaults');
var Types = xdc.useModule( 'xdc.runtime.Types');
Defaults.memoryPolicy = Types.STATIC_POLICY;

7.7.2 指定默认系统堆
BIOS模块为SYS/BIOS的使用创建一个默认heap。当在运行时调用带空heap的Memory_alloc()时,此系统heap将被使用。由BIOS模块创建的默认系统heap是一个HeapMem实例。BIOS模块提供以下和系统heap相关的配置参数:
  • BIOS.heapSize:可用于设置系统heap尺寸。
  • BIOS.heapSection:可被用于放置系统heap。
例如,你可以配置默认系统heap如下:
var BIOS = xdc.useModule( 'ti.sysbios.BIOS');
BIOS.heapSize = 0x900;
BIOS.heapSection =  "systemHeap";
如果你希望对系统heap使用不同的heap管理器,可以在你的配置文件中指定系统heap,SYS/BIOS不会重写设置。

注意:SYS/BIOS系统heap不能为HeapStd实例。BIOS模块会检测此条件并生成一个错误信息。

以下配置声明使用HeapBuf而不是HeapMem指定了一个系统heap:
/* Create a heap using HeapBuf */
var heapBufParams =  new HeapBuf.Params;
heapBufParams.blockSize =  128;
heapBufParams.numBlocks =  2;
heapBufParams.align =  8;
heapBufParams.sectionName =  "myHeap";
Program.global.myHeap = HeapBuf.create(heapBufParams);

Program.sectMap[ "myHeap"] =  "DDR";
Memory.defaultHeapInstance = Program.global.myHeap;
如果你不创建一个系统heap,可以将BIOS.heapSize设置为0。BIOS模块将使用HeapNull实例来最小化代码/数据使用。

7.7.3 使用xdc.runtime.Memory模块
所有动态分配都是通过xdc.runtime.Memory模块完成的。内存模块提供诸如Memory_alloc()和Memory_free()的APIs。所有内存APIs都以一个IHeap_Handle作为它们的第一个参数。内存模块自己做非常少的工作;它通过IHeap_Handle来调用Heap模块。Heap模块负责管理内存。使用内存API使应用程序和中间件可移植,不依赖于特定的堆实现。

可通过静态或动态创建Heap实例以实现IHeap_Handles和内存APIs的一起使用。当内存APIs所传递的IHeap_Handle为空时,会使用系统默认heap。详见7.7.2节。

运行时例子:此例从两个不同的heaps分配和释放内存。它通过给Memory_allocc传递空的IHeapHandle来从系统heap进行分配。通过显示传递“otherHeap”句柄,来从一个叫“otherHeap”的单独heap进行分配。
#include <xdc/std.h>
#include <xdc/runtime/IHeap.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Memory.h>
#include <xdc/runtime/Error.h>
extern IHeap_Handle systemHeap, otherHeap;
Void main()
{
    Ptr buf1, buf2;
    Error_Block eb;
    Error_init(&eb);
     /* Alloc and free using systemHeap */
    buf1 = Memory_alloc( NULL1280, &eb);
     if (buf1 ==  NULL)
    {
        System_abort( "Memory allocation for buf1 failed");
    }
    Memory_free( NULL, buf1,  128);
     /* Alloc and free using otherHeap */
    buf2 = Memory_alloc(otherHeap,  1280, &eb);
     if (buf2 ==  NULL)
    {
        System_abort( "Memory allocation for buf2 failed");
    }
    Memory_free(otherHeap, buf2,  128);
}

7.7.4 为模块的动态实例指定堆
你可在为动态创建的模块实例分配内存时指定一个默认heap。控制所有模块的默认堆的配置属性是Default.common$.instanceHeap。

例如,以下配置声明为分配的实例指定heap:
var HeapMem = xdc.useModule( 'ti.sysbios.heaps.HeapMem');
var heapMemParams =  new HeapMem.Params;
heapMemParams.size =  8192;
var heap1 = HeapMem.create(heapMemParams);
Default.common$.instanceHeap = heap1;

如果不为实例指定另外的heap,将会使用Memory.defaultHeapInstance作为指定heap(见7.7.2节)。

在为动态创建实例分配内存时,要为特定模块指定一个heap,应为此模块设置instanceHeap参数。例如,以下配置声明为Semaphore模块指定了一个heap:

var Semaphore = xdc.useModule( 'ti.sysbios.knl.Semaphore');
var HeapMem = xdc.useModule( 'ti.sysbios.heaps.HeapMem');

var heapMemParams =  new HeapMem.Params;
heapMemParams.size =  8192;
var heap1 = HeapMem.create(heapMemParams);

Semaphore.common$.instanceHeap = heap1;

7.7.5 使用malloc()和free() 
应用程序可以调用malloc()和free()函数。通过这些函数由代码生成工具所配备的RTS库提供。尽管如此,当使用SYS/BIOS时,这些函数由SYS/BIOS提供并重定向分配到默认系统堆(见7.7.2节)。

改变heap尺寸请使用malloc(),并使用BIOS.heapSize配置参数。

7.8 Heap实现
 xdc.runtime.Memory模块是所有内存操作的公共接口。实际的内存管理工作是由Heap实例实现的,如HeapMem或HeapBuf实例。例如,Memory_alloc()用于在运行时动态分配内存。所有内存APIs都携带一个Heap实例作为参数。实际上,内存模块调用的是heap的接口函数。

SYS/BIOS提供以下Heap实现:
  • HeapMin:最小代码占用实现。支持内存分配,但不支持内存释放。见7.8.1节。
  • HeapMem:分配可变尺寸块。见7.8.2节。
  • HeapBuf:分配固定尺寸块。见7.8.3节。
  • HeapMultiBuf:指定可变尺寸的分配,但实际上从各种固定尺寸块分配。见7.8.4节。
  • HeapTrack:用于检测内存分配和释放问题。见7.8.5节

下表比较各种SYS/BIOS堆实现。参考CDOC帮助获取详细信息。
基于TI-RTOS的CC2650DK开发(18)---Stacks(栈)和Heap(堆) - 阿巴睇 - 阿巴睇的博客
 不同的heap实现针对不同的内存管理特性进行优化。HeapMem模块接受所有可能尺寸块的请求,所以它最大限度地减少内部碎片。HeapBuf模块从另一方面来说,仅能分配固定尺寸块,所以它最大限度地减少了堆的外部碎片,并更快地分配和释放内存。

7.8.1 HeapMin
HeapMin是最少堆占用实现。此模块为那些通常只在运行时分配内存和创建模块实例的应用程序而设计,但从不显式地删除所创建的实例或释放内存。

HeapMin不支持释放内存。默认情况下,一个调用HeapMin_free()的应用程序会中止于错误状态。可通过设置HeapMin.freeError配置参数为“false”在发生错误的情况下使得HeapMin_free()只是简单地返回。

如果在运行时调用HeapMin_create(),应用程序将负责指定缓冲区,heap将管理和对齐缓冲区。

如果在静态配置中创建HeapMin实例,heap将对齐至支持静态对齐的目标的最大对齐需求。对于不支持静态对齐的目标来说,缓冲区对齐是未定义的。

7.8.2 HeapMem
HeapMem可被认为是最灵活的堆,因为它允许你分配可变尺寸块。当直到运行时还未知道内存需求时,可使用它每次对内存所需进行正确分配。例如,如果程序需要存储一个数组的对象,直到程序实际运行时还未知对象的数量,数组适合于从HeapMem进行分配。

HeapMem所提供的灵活性包含了一些性能上的权衡。
  • 外部碎片:分配可变尺寸块会导致碎片。当内存块释放回给HeapMem,会导致HeapMem中的可用内存分散在堆各处。HeapMem中的可用空间总数可能很大,但由于它的不连续,Heap中仅有和“碎片”一样大的块可以被分配。

这种类型的碎片被称为“外部”碎片,因为块本身被精确分配尺寸,所以碎片分布于整个heap,它对于块本身是“外部”的。
  • 非确定性执行:当HeapMem管理的内存成为碎片,可用内存块存储在链表上。必须遍历此链表才能找到合适的块。因为此列表可以有不同长度,它无法预知所要分配的长度,所以执行变得“非确定”。

关于HeapMem的最佳使用方法的一些建议:
  • 大块优先:如果可能,首先分配更大的块。之前分配的小内存块会减少大内存分配的可用块尺寸。
  • 高估堆大小:考虑到碎片的负面影响,可能需要使用一个明显大于程序绝对内存量的HeapMem。

当一个块释放回HeapMem,HeapMem会将块与邻近空闲块结合,从而使得块尺寸尽可能地大。
注意:HeapMem使用了一个用户提供锁来锁定访问内存。详细信息请参考4.3节:Gates

下例创建了一个带1024大小MAUs的HeapMem实例。
配置实例:此例为静态配置堆:
var HeapMem = xdc.useModule( 'ti.sysbios.heaps.HeapMem');
/* Create heap as global variable so it can be used in C code */
var heapMemParams =  new HeapMem.Params();
heapMemParams.size =  1024;
Program.global.myHeap = HeapMem.create(heapMemParams);

运行时实例:第二个例子使用C为动态创建HeapMem实例:
HeapMem_Params prms;
static  char buf[ 1024];
HeapMem_Handle heap;
Error_Block eb;
Error_init(&eb);
HeapMem_Params_init(&prms);
prms.size =  1024;
prms.buf = (Ptr)buf;
heap = HeapMem_create(&prms, &eb);
if (heap ==  NULL)
{
    System_abort( "HeapMem create failed");
}

HeapMem使用Gate来防止空闲块的HeapMem列表操作代码的并发访问。HeapMem所使用的Gate类型由HeapMem的公共默认文件静态配置。

配置实例:此例使用GateMutexPri配置HeapMem以保护关键区域代码。
var GateMutexPri = xdc.useModule( 'ti.sysbios.gates.GateMutexPri');
var HeapMem = xdc.useModule( 'ti.sysbios.heaps.HeapMem');
HeapMem.common$.gate = GateMutexPri.create();

Gate类型的使用取决于应用程序所需的保护等级。如果堆不存在并发访问的风险,可以赋“null”值以放弃使用任何Gate,这将提升性能。对于可能存在并发访问的应用程序,GateMutex是合适的选择。或者,如果一个关键线程需要HeapMem的同时,还是一个低优先级线程,那么GateMutexPri将是最适用于确保关键线程尽可能快地接受访问HeapMem。参考4.3.2.2节获取更多GateMutexPri信息。

7.8.3 HeapBuf
HeapBuf用于分配固定尺寸内存块,被设计为快速和确定性。通过用于创建和删除一个固定尺寸对象的可变数量实例。HeapBuf为这样的对象分配空间是最理想的,因为它可以快速处理请求并且不产生任何碎片。

当响应时间比内存使用效率更重要时,HeapBuf也可用于分配可变尺寸对象。在此种情况下,HeapBuf将出现“内 部”碎片。这使得整个堆中不会出现任何碎片空间,但分配的块自身会包含有浪费的空间,所以碎片对分配块来说是“内部”的。

HeapBuf中内在的分配和释放花费相同的时间,所以HeapBuf是“确定性”内存管理器。

下例创建了一个带10个128大小内存块的HeapBuf。
配置实例:第一个例子静态地配置heap。在此例中,无需指定buffer或bufSize参数,因为配置在链接时可计算这些值并分配正确的片。
var HeapBuf = xdc.useModule( 'ti.sysbios.heaps.HeapBuf');
/* Create heap as global variable so it can be used in C code */
var heapBufParams =  new HeapBuf.Params();
heapBufParams.blockSize =  128;
heapBufParams.numBlocks =  10;
Program.global.myHeap = HeapBuf.create(heapBufParams);

运行时实例:第二个例子使用C代码动态创建HeapBuf实例。在此例中,你必须传递bufSize和buf参数。注意,在指定这些运行时参数时,blocksize需要设为结构体最坏情况下对齐尺寸的数倍大小,而bufSize应等于blockSize * numBlocks。最坏情况结构体对齐是目标依赖的。在C6x和ARM设备中,此值为8。缓中基地址也应该对齐至相同尺寸。
HeapBuf_Params prms;
static  char buf[ 1280];
HeapBuf_Handle heap;
Error_Block eb;
Error_init(&eb);
HeapBuf_Params_init(&prms);
prms.blockSize =  128;
prms.numBlocks =  10;
prms.buf = (Ptr)buf;
prms.bufSize =  1280;
heap = HeapBuf_create(&prms, &eb);
if (heap ==  NULL)
{
    System_abort( "HeapBuf create failed");
}

7.8.4 HeapMultiBuf
HeapMultiBuf意在平衡HeapMem和HeapBuf的优点。本质上,HeapMultiBuf包含了一个HeapBuf实例集合,每个实例拥有不同的块尺寸、对齐和块数量。HeapMultiBuf实例可接受任意尺寸的内存,并易于决定从哪个HeapBuf分配。

HeapMultiBuf相对单个HeapBuf,提供了更多的灵活性,但仍在很大程序上保留了HeapBuf的快速性能。HeapMultiBuf实例遍历寻找分配HeapBuf的额外开销。但在实践中,不同尺寸块的数量通过很少,且尺寸固定,所以HeapMultiBuf可在某些条件下认定为“确定性”的。

HeapMultiBuf服务于任意内存尺寸请求,但通常返回一个固定尺寸块。分配将不返回有关所分配的块的实际大小的任何信息。当将块释放回HeapMultiBuf,size参数被忽略。HeapMultiBuf通过对比地址来决定释放块所在的缓冲。

当HeapMultiBuf在它的一个缓冲中运行时超出块的范围,可被配置为从下一个最大缓冲分配块。这被称为“块借用”。阅读在线参考1.6.1节获取更多HeapMultiBuf信息。

下例创建了一个管理1024 MAUs内存的HeapMultiBuf,被分为3个缓冲区。它管理着8个16MAUs块,8个32MAUs块和5个128MAUs块。如下图所示:
基于TI-RTOS的CC2650DK开发(18)---Stacks(栈)和Heap(堆) - 阿巴睇 - 阿巴睇的博客
 
配置实例:第一个例子静态配置HeapMultiBuf实例:
var HeapMultiBuf = xdc.useModule( 'ti.sysbios.heaps.HeapMultiBuf');
/* HeapMultiBuf without blockBorrowing. */
/* Create as a global variable to access it from C Code. */
var heapMultiBufParams =  new HeapMultiBuf.Params();
heapMultiBufParams.numBufs =  3;
heapMultiBufParams.blockBorrow =  false;
heapMultiBufParams.bufParams =
[{blockSize:  16, numBlocks: 8, align:  0},
{blockSize:  32, numBlocks: 8, align:  0},
{blockSize:  128, numBlocks: 5, align:  0}];
Program.global.myHeap =
HeapMultiBuf.create(heapMultiBufParams);

运行时实例:第二个例子使用C代码动态创建HeapMultiBuf实例:
HeapMultiBuf_Params prms;
HeapMultiBuf_Handle heap;
Error_Block eb;

Error_init(&eb)
/* Create the buffers to manage */
Char buf0[ 128];
Char buf1[ 256];
Char buf2[ 640];
/* Create the array of HeapBuf_Params */
HeapBuf_Params bufParams[ 3];

/* Load the default values */
HeapMultiBuf_Params_init(&prms);
prms.numBufs =  3;
prms.bufParams = bufParams;

HeapBuf_Params_init(&prms.bufParams[ 0]);
prms.bufParams[ 0].align =  0;
prms.bufParams[ 0].blockSize =  16;
prms.bufParams[ 0].numBlocks =  8;
prms.bufParams[ 0].buf = (Ptr) buf0;
prms.bufParams[ 0].bufSize =  128;

HeapBuf_Params_init(&prms.bufParams[ 1]);
prms.bufParams[ 1].align =  0;
prms.bufParams[ 1].blockSize =  32;
prms.bufParams[ 1].numBlocks =  8;
prms.bufParams[ 1].buf = (Ptr) buf1;
prms.bufParams[ 1].bufSize =  256;

HeapBuf_Params_init(&prms.bufParams[ 2]);
prms.bufParams[ 2].align =  0;
prms.bufParams[ 2].blockSize =  128;
prms.bufParams[ 2].numBlocks =  5;
prms.bufParams[ 2].buf = (Ptr) buf2;
prms.bufParams[ 2].bufSize =  640;

heap = HeapMultiBuf_create(&prms, &eb);
if (heap ==  NULL)
{
    System_abort( "HeapMultiBuf create failed");
}

7.8.5 HeapTrack
HeapTrack是缓冲管理模块,跟踪所有当前为任意heap实例所分配的块。HeapTrack常用于检测内存泄漏、缓冲区溢出和内存块双释放。任何XDCtools或SYSBIOS堆实例都可以插入HeapTrack。对于每一次内存分配,都会加入额外的数据包。这个数据由RTOS Object View (ROV)用于显示heap实例相关信息。

HeapTrack实现了默认heap函数以及两个调试函数。第一个HeapTrack_printHeap()打印所有给定HeapTrack实例的内存块。第二个HeapTrack_printTask()打印所有给定Task句柄的内存块。

HeapTrack有几个断言用于检测关键内存错误。这些包括释放同一个内存块两次、分配的内存块溢出、检测非空heap实例和调用带空heap对象的Track_printHeap。

使用HeapTrack会产生性能和空间上的间接成本。当设置heap和缓冲区尺寸时,这些应该被考虑在内。

你可以在C代码中通过使用 sizeof(HeapTrack_Tracker)来找哪计算出HeapTrack模块所增加的块尺寸的数量。此数量是在你的代码或其它函数从HeapTrack所管理的heap调用Memory_alloc()时所增加的尺寸。HeapTrack_Tracker结构体会添加到分配块的末端;因此HeapTrack不会影响分配块的对齐。

配置实例:引例为一个已存heap静态配置HeapTrack。
var HeapTrack = xdc.useModule( 'ti.sysbios.heaps.HeapTrack');
var heapTrackParams =  new HeapTrack.Params();
heapTrackParams.heap = heapHandle;
Program.global.myHeap = HeapTrack.create(heapTrackParams);

你也可以通过设置heapTrackEnabled配置参数让BIOS模块的默认heap使用HeapTrack。
var BIOS = xdc.useModule( 'ti.sysbios.BIOS');
BIOS.heapTrackEnabled =  true;

运行时实例:此例使用C代码为已存heap动态创建HeapTrack实例。
HeapTrack_Params prms;
HeapTrack_Handle heap;
Error_Block eb;
Error_init(&eb);
HeapTrack_Params_init(&prms);
prms.heap = heapHandle;
heap = HeapTrack_create(&prms, &eb);
if (heap ==  NULL)
{
    System_abort( "HeapTrack create failed");
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值