TI-RTOS Kernel User‘s Guide:7---Memory

介绍在SYS/BIOS中使用内存的相关问题.

7.1Background

本章讨论静态内存的配置(即内存映射和节放置)、缓存和堆栈。它还提供有关动态内存分配的信息(在运行时分配和释放内存)。

静态内存配置与可执行文件可用的“内存映射”以及将代码和数据放置到内存映射中有关。内存映射由存在于CPU内的内部内存区域和位于硬件板上的外部内存区域组成。有关内存映射的详细信息,请参见7.2节

链接器使用链接器命令文件将代码和数据放置在内存区域中。链接器命令文件指定内存映射。对于每个内存区域,链接器命令文件指定起始地址或基址、长度和属性(读、写和执行)。在链接器命令文件中指定的内存区域也称为“内存段”。

以下是链接器命令文件中的内存映射规范:

MEMORY {
    IRAM (RWX) : org = 0x800000, len = 0x200000
    DDR : org = 0x80000000, len = 0x10000000
}

链接器命令文件还包含有关“内存段”位置的信息,如下面的示例所示。节是由编译器生成的可重新定位的代码块。编译器为各种类型的代码和数据生成一些著名的节,例如:.text、.switch、.bss、.far、.cinit和.const。有关详细信息,请参阅相应的编译器用户指南。

SECTIONS {
 .text: load >> DDR
 .switch: load >> DDR
 .stack: load > DDR
 .vecs: load >> DDR
 .args: load > DDR
 .sysmem: load > DDR
 .far: load >> DDR
 .data: load >> DDR
 .cinit: load > DDR
 .bss: load > DDR
 .const: load > DDR
 .pinit: load > DDR
 .cio: load >> DDR
}

链接器将“内存段”(如。text和。cinit)放入链接器命令文件的sections部分指定的“内存段”(如IRAM)中。有关Section放置的详细信息,请参见章节7.3

7.2Memory Map

可执行文件的内存映射由设备(具有内部内存)和硬件板(具有外部内存)决定。

当使用SYS/BIOS的应用程序创建CCS项目时,可以在RTSC Configuration Settings页面上选择一个平台,设备内存储器和外部存储器的内存映射由该平台确定,还可以设置时钟速度并指定内存段的位置。在创建新项目或更改项目构建属性时选择平台,而不是在创建配置文件时选择平台。需要不同内存映射的可执行文件必须使用不同的平台,即使它们运行在相同类型的主板上。

该平台绑定到一个特定的设备(CPU),并从该设备获取内部内存映射——例如,IRAM和FLASH。该平台还包含外部内存规格和缓存设置。内部和外部内存段共同构成内存映射。

7.2.1选择一个可用的平台

在构建SYS/BIOS 6.x可执行文件,需要选择使用的硬件板子。平台字段提供了与目标匹配的所有可用平台的下拉列表;这些下拉列表可用于您所选设备(CPU)的各种评估板。

要查看平台( platform)的内存映射(memory map ),选择打开平台向导 Tools > RTSC 
Tools > Platform > Edit/View.选择SYS/BIOS安装中的包存储库(<bios_install_dir>\packages directory))

在大多数情况下,您使用其中一个评估板开始应用程序开发,并且可以从下拉列表中选择一个标准平台。如符合下列各项,你应选择其中一个现有平台:

(1)开发阶段使用评估版

(2)不关心缓存大小,并且对现有平台设置的默认值感到满意

(3)不希望更改默认的部分位置。

(4)需要与评估板相同的时钟速率。

7.2.2创建自定义平台

在应用程序开发过程中的某个时刻,大多数客户构建自己的电路板,选择TI器件并添加自定义外部存储器。如果符合以下任何一项,您还需要创建自己的平台:

(1)需要自定义缓存大小。

(2)希望手动覆盖默认的部分位置。

对于这种自定义板,您需要使用平台向导创建一个平台。平台向导是一个GUI工具,允许您轻松地创建自定义平台。在定义内存映射和选择用于分段放置的默认内存段方面,创建自定义平台为您提供了很大的灵活性.要运行平台向导,请执行以下步骤:

(1)在CCS,选择tools> RTSC Tools > Platform > New ,将打开新平台向导

(2)命名包,是为项目选择选择的平台名称,是包含平台包的目录名字。

您可以使用简单的名称或以句点分隔的名称。周期对应于创建平台包时的目录级别。

如果将 C:\myRepository\packages 作为存储库位置,创建C:\myRepository\packages\myBoards\DA830_bigCache --->myBoards.DA830_bigCache 

(3)在平台包存储库字段旁边点击浏览,选择要在其中保存平台包的存储库的位置

如果您以前没有创建过包存储库,并且不想使用默认的存储库,那么创建一个新目录来包含该存储库。在您选择的目录中,创建名为“packages”的子目录。例如,您可以使用C:\myRepository\packages作为存储库。存储库的完整路径不应该包含任何空格。

(4)勾选上图的add Repository to project package path

(5)选择设备簇和设备名称

(6)点击 Next 将看到设备页的平台向导( Device Page of the platform wizard)

如果您希望另一个项目能够使用该平台,您可以稍后将包含该平台的存储库添加到项目的属性中,方法是右键单击项目并选择Build properties。选择“CCS General”类别,然后选择“RTSC”页签。单击Add并浏览您希望项目能够搜索平台的存储库的文件系统。

7.2.2.1获取和设置时钟速度和默认内存设置

设备页打开时没有时钟速度设置,没有外部内存段,也没有内存段分配。通常,您要做的第一件事是从现有平台导入默认设置,以便您可以使用这些设置作为进行所需修改的基础.导入默认设置步骤:

单击时钟速度字段旁边的导入按钮,在Select Platform对话框中,选择要导入其默认值的平台,然后单击OK。在询问您是否确定要更改设置的确认对话框中单击Yes。您可以看到默认的时钟速度和外部内存设置。如果你愿意,你可以换这些。

7.2.2.2确定自定义平台的缓存大小

由于缓存大小会影响内存映射,如果您使用的是C6000目标,那么在创建平台时需要决定要使用的大小。例如,如果您正在使用“ti.平台。在evmDA830”平台上,L1P、L1D和L2缓存大小会影响可用的L1PSRAM、L1DSRAM和IRAM的大小。

由于缓存大小是在平台中设置的,因此需要不同缓存配置的可执行文件也需要不同的平台。下面的示例步骤使用平台向导的设备页面来指定TMS320DA830平台的最大缓存大小:

将 L1D Cache设置为32K,设置 L1P Cache为32K,设置 L2 Cache为256K。

 L1PSRAM, L1DSRAM and IRAM 的大小可调整至0

7.2.2.3为数据、代码和堆栈选择默认内存段

平台还确定用于放置代码、数据和堆栈的默认内存段。如果没有显式放置节,则使用默认值。例如,如果您没有在*.cfg文件中配置任务堆栈的位置,那么任务堆栈将被放置在平台指定的堆栈内存段中。通过在平台定义中选择数据内存、代码内存和堆栈内存的值,您可以粗略地决定代码、数据和堆栈的放置位置。例如在evmDA830上,您可能希望代码在SDRAM中,数据在RAM中。您可以通过在平台向导中选择代码内存为SDRAM和数据内存为IRAM来实现这一点。

7.2.2.4设置段的自定义基址和长度

您可以自定义内部和外部内存段的名称、位置、大小、类型和访问.要自定义内部内存段,请先选中“设备内存”区域中的“自定义内存”框。然后,您可以单击内存段列表中的字段并进行更改。在“名称”、“基数”和“长度”列中,键入要使用的值。在Space和Access列中,您可以从选项列表中进行选择。

7.3Placing Sections into Memory Segments

Sections:code, data, stack

Memory Segments

 要定义和放置不受SYS/BIOS管理的新Sections,您可以修改项目的配置文件(.cfg),如第7.3.1节和第7.3.2节所述,或者提供一个补充的链接器命令文件,如第7.3.3节所述。要修改由SYS/BIOS管理的节的位置,您可以修改项目的配置(.cfg)文件,如第7.3.1和7.3.2节所述,或者提供您自己的链接器命令文件来替换部分或全部生成的链接器命令文件,如第7.3.4节所述。

要在*.cfg文件中将部分放入段中,您需要在文本编辑器中编辑*.cfg脚本的源代码。目前,不能使用XGCONF GUI编辑器。

7.3.1Configuring Simple Section Placement

在配置文件中, section 位置通过 Program.sectMap[] 数组指定,配置section位置(段)的最简单方法如下:

Program.sectMap[".foo"] = "IRAM"; //这个示例将导致IRAM段同时用于加载和运行.foo节

7.3.2 Configuring Section Placement Using a SectionSpec

 Program.sectMap[] 数组将section名称映射到SectionSpec类型的结构。使用SectionSpec结构可以更精确地控制如何指定section的运行和加载内存段(或地址)。SectionSpec结构包含以下字段:

runSegment;  //
runSegment;
runAddress;  //运行的地址,不能同时指定runAddress和runSegment
loadAddress;  //加载的地址,不能同时指定loadAddress和runSegment
runAlign;     //对runSegment指定的部分进行对齐
loadAlign;    //对loadSegment指定的部分进行对齐
type;         //使用此字段定义各种特定于目标的标志以标识节类型,如COPY、DSECT、NOLOAD
fill;         //如果指定此值用于初始化未初始化的节

//配置文件.cfg
Program.sectMap[".foo"] = new Program.SectionSpec();
Program.sectMap[".foo"].loadSegment = "FLASH";
Program.sectMap[".foo"].runSegment = "RAM";

Program.sectMap[".text:_ti_sysbios_knl_Swi_post__F"] = new Program.SectionSpec();
Program.sectMap[".text:_ti_sysbios_knl_Swi_post__F"] = "IRAM";

var Task = xdc.useModule('ti.sysbios.knl.Task');
Task.common$.instanceSection = ".taskStatic";
Program.sectMap[".taskStatic"] = new Program.SectionSpec();
Program.sectMap[".taskStatic"].loadSegment = "IRAM";

7.3.3Providing a Supplemental Linker Command File

可以提供您自己的链接器命令文件来补充XDCtools生成的链接器命令文件。您可以这样做来定义新的部分,并利用链接器命令语言提供的所有特性。只需添加一个已写入CCS项目的链接器命令文件。该文件的扩展名为“*.cmd”。CCS会自动识别这样的链接器命令文件,并在链接步骤中调用它。内存映射的定义(链接器命令文件的“memory”规范)由您的平台处理,因此此方法不能用于更改现有内存段的定义。这种方法适用于定义新的内存段。如果你想改变由SYS/BIOS管理的Section的位置,你必须遵循第7.3.1、7.3.2或7.3.4节中描述的方法之一。

7.3.4Default Linker Command File and Customization Options

SYS/BIOS应用程序使用的链接器命令文件是在处理配置时自动生成的。该命令文件通常位于配置包中,如下所示:自动生成的链接器命令文件使用与程序关联的平台指定的模板。这个命令文件定义了在配置过程中确定的MEMORY和SECTIONS。配置文件中各节的位置反映在这个自动生成的命令文件中

7.5Stacks

SYS/BIOS为硬件中断使用单个系统堆栈,为每个task实例使用单独的任务堆栈

7.5.1System Stack

您可以配置System堆栈的大小,它用作硬件中断和软件中断的堆栈(如果Task被禁用,则由Idle函数使用)。您应该设置系统堆栈大小以满足应用程序的需要。有关系统堆栈大小要求的信息,请参见3.5.3节。您可以使用.stack部分来控制系统堆栈的位置。例如,下面的配置语句将大小为0x400的系统堆栈放在IRAM段中.

Program.stack = 0x400;
Program.sectMap[".stack"] = "IRAM";

设置程序。Stack在链接器命令文件中生成适当的链接器选项,以允许在链接时分配系统堆栈。例如,C6000应用程序的链接器命令文件可能包含命令选项 -stack 0x0400

有关与系统堆栈大小和位置相关的符号,请参阅项目的自动生成链接器命令文件。对于C6000,这些包括__TI_STACK_END和__STACK_SIZE。

7.5.2Task Stacks

如果Task模块被启用,SYS/BIOS为应用程序包含的每个Task实例创建一个额外的堆栈(加上一个空闲线程的任务堆栈)。关于任务栈大小的要求请参见3.6.3章节.您可以在配置文件中指定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);

/* Place idle task stack section */
Program.sectMap[".idleTaskStackSection"] = "IRAM";
/* Place other static task stacks */
Program.sectMap[".taskStackSection"] = "IRAM";

7.6Cache Configuration

C6000在SYS/BIOS中的cache大小。X是由你选择的平台决定的。要更改缓存大小,请使用第7.2.2.2节中描述的平台向导创建或修改平台。下面的小节描述了在SYS/BIOS中使用家族指定的Cache模块来操作缓存行为的方法。

7.6.1Configure Cache Size Registers at Startup

对于C6000目标, ti.sysbios.hal.Cache模块从平台获取缓存大小,并在启动时设置寄存器缓存大小。ti.sysbios.hal.Cache模块是一个通用模块,在特定族 ti.sysbios.family.*.Cache 模块实现。

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

7.6.2Configure Parameters to Set MAR Registers

对于C6000目标, ti.sysbios.family.c64p.Cache 模块定义Cache.MAR##-## 配置参数,这允许控制外部内存地址是否可可缓存。如Cache_MAR128_159 就是这样一个配置参数。这些配置参数直接映射到设备上的MAR寄存器,每个16MB的外部内存地址空间由1个MAR位控制(0:不可缓存,1:可缓存)。SYS/BIOS Cache模块具有映射到MAR寄存器的全模块配置参数。默认情况下,C64P缓存模块通过将所有相应的MAR位设置为0x1,使平台中定义的所有内存区域都可缓存。要在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位后,CPU访问的新地址将缓存在L2缓存中,或者如果L2被禁用,则缓存在L1中。有关MAR寄存器及其到外部内存地址的映射,请参阅特定于设备的参考指南。在系统启动时,Cache模块写入MAR寄存器并配置它们。

7.6.3 Cache Runtime APIs

对于任何具有缓存的目标,ti.sysbios.hall.Cache模块提供了在运行时操作缓存的APIs。这些APIs包括Cache_enable()、Cache_disable()、Cache_wb()和Cache_inv()。详细信息请参见8.4.1节。

7.7Dynamic Memory Allocation

Heap是一个实现IHeap接口的模块,堆是动态内存管理器,管理特定的内存块,并支持分配和释放该内存块。内存分配大小以内存的“最小可寻址单元”(MAUs)来衡量。MAU是CPU可以读写的最小数据存储单元。对于C28x,这是一个16位字。对于所有其他当前支持的目标系列(包括C6000、ARM和msp430),这是一个8位字节。

7.7.1Memory Policy

可以通过在全局或每个模块的基础上设置memoryPolicy来减少应用程序使用的代码空间量,这在代码内存明显受限的目标上特别有用。

(1)DELETE_POLICY:应用程序在运行时创建和删除对象(或此模块的对象)。您需要MODULE_create()函数和MODULE_delete()函数对应用程序都可用。

(2)CREATE_POLICY:应用程序在运行时创建对象(或此模块的对象),它不会在运行时删除对象。您需要MODULE_create()函数对应用程序可用,但不需要MODULE_delete()函数。

(3)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.2Specifying the Default System Heap

BIOS模块创建一个默认堆供SYS/BIOS使用。当Memory_alloc()在运行时使用NULL堆调用时,将使用这个系统堆。BIOS模块创建的默认系统堆是一个HeapMem实例。BIOS模块提供如下与系统堆相关的配置参数:BIOS.heapSize设置系统堆大小,BIOS.heapSection设置系统堆位置

var BIOS = xdc.useModule('ti.sysbios.BIOS');
BIOS.heapSize = 0x900;
BIOS.heapSection = "systemHeap";

如果希望为系统堆使用不同的堆管理器,可以在配置文件中指定系统堆,SYS/BIOS将不会覆盖该设置。

SYS/BIOS系统堆不能是HeapStd实例。BIOS模块检测到这种情况,并产生错误信息。

下面的配置语句指定一个使用HeapBuf而不是HeapMem的系统堆:

/* 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;

如果不希望创建系统堆,可以设置BIOS。heapSize为0。然后,BIOS模块将使用HeapNull实例来最小化代码/数据使用

7.7.3Using the xdc.runtime.Memory Module

所有动态分配都是通过xdc.runtime.Memory模块完成的。Memory模块提供了Memory_alloc()和Memory_free()等api。所有内存api都将IHeap_Handle作为它们的第一个参数。内存模块本身做的工作很少;它通过IHeap_Handle调用Heap模块。Heap模块负责管理内存。使用内存api可以使应用程序和中间件具有可移植性,而不必绑定到特定的堆实现。与内存api一起使用的IHeap_Handles可以通过静态或动态创建堆实例获得。当传递给内存api的IHeap_Handle为NULL时,使用默认的系统堆。参见第7.7.2节。

这个示例从两个不同的堆分配和释放内存。它通过将NULL作为IHeap_Handle传递给Memory_alloc来从系统堆中分配内存。它通过显式地传递“otherHeap”句柄,从一个名为“otherHeap”的单独堆中进行分配。

#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(NULL, 128, 0, &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, 128, 0, &eb);
   if (buf2 == NULL) {
      System_abort("Memory allocation for buf2 failed");
   }
   Memory_free(otherHeap, buf2, 128);
}

7.7.4Specifying a Heap for Module Dynamic Instances

您可以指定在为动态创建的模块实例分配内存时使用的默认堆。控制所有模块的默认堆的配置属性是default .common$. instanceheap。

例如,这些配置语句指定用于分配实例的堆:

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;

如果您没有为实例指定单独的堆,则将使用为Memory.defaultHeapInstance指定的堆(参见第7.7.2节)。

要指定特定模块在为动态创建的实例分配内存时使用的堆,请设置该模块的instanceHeap参数。例如,以下配置语句指定了信号灯模块的堆:

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.5Using malloc() and free()

应用程序可以调用malloc()和free()函数。通常,这些功能是由代码生成工具提供的RTS库提供的。但是,当您使用SYS/BIOS时,这些函数由SYS/BIOS提供,并将分配重定向到默认的系统堆(参见第7.7.2节)。要更改malloc()使用的堆的大小,请使用BIOS。heapSize配置参数.

7.8Heap Implementations

memory模块是所有内存操作的通用接口。实际的内存管理是由Heap实例执行的,例如HeapMem或HeapBuf实例。例如,Memory_alloc()在运行时用于动态分配内存。所有的内存api都将Heap实例作为它们的参数之一。在内部,Memory模块调用堆的接口函数

SYS/BIOS提供了以下堆实现:

HeapMin:非常小的代码占用实现。支持内存分配,但不支持释放内存。

HeapMem:分配可变大小的块

HeapBuf:分配固定大小的块

HeapMultiBuf:指定可变大小的分配,但在内部从各种固定大小的块分配

HeapTrack:用于检测内存分配和回收问题

该表比较了SYS/BIOS堆实现

不同的堆实现针对不同的内存管理特性进行优化。HeapMem模块(第7.8.2节)接受所有可能大小的块的请求,因此它将内部碎片最小化。另一方面,HeapBuf模块(第7.8.3节)只能分配固定大小的块,因此它可以最大限度地减少堆中的外部碎片,并且在分配和释放内存方面也更快.

7.8.1HeapMin

HeapMin是一个最小占用堆实现。此模块专为通常在运行时分配内存和创建模块实例,但从不删除已创建的实例或显式释放内存的应用程序而设计。

HeapMin不支持释放内存。默认情况下如果调用HeapMin_free(),应用程序将以错误状态终止。可以将HeapMin.freeError配置参数设置为"false",以使HeapMin_free()只返回而不引发错误。如果在运行时调用HeapMin_create(),则应用程序负责指定堆将管理的缓冲区并对齐缓冲区。

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

7.8.2HeapMem

HeapMem可以被认为是堆中最“灵活”的,因为它允许您分配可变块。当直到运行时才知道内存请求的大小时,理想的做法是能够准确地分配每次需要多少内存。例如,如果程序需要存储一个对象数组,并且在程序实际执行之前不知道所需对象的数量,则可能需要从HeapMem中分配该数组。

HeapMem提供的灵活性有许多性能折衷。

External Fragmentation:分配可变大小的块可能导致碎片。当内存块被“释放”回HeapMem时,HeapMem中的可用内存分散在堆中。HeapMem中的空闲空间总量可能很大,但由于它不是连续的,因此只能分配与堆中的“片段”一样大的块。这种类型的碎片被称为“外部”碎片,因为块本身是完全按照大小分配的,所以碎片位于整个堆中,并且是块本身的“外部”碎片。

Non-Deterministic Performance:当HeapMem管理的内存变成碎片时,可用的内存块存储在一个链表中。要分配另一个内存块,必须遍历该列表以找到合适的块。由于这个列表的长度可以变化,因此不知道分配请求将花费多长时间,因此性能变得“不确定”。

有许多建议可以帮助您最佳地使用HeapMem:

Larger Blocks First:如果可能的话,先分配较大的块。以前分配的小内存块会减少可用于更大内存分配的块的大小。

Overestimate Heap Size:要考虑到碎片的负面影响,请使用比程序可能需要的绝对内存量大得多的HeapMem

当一个块被释放回HeapMem时,HeapMem将该块与相邻的空闲块结合起来,使可用块的大小尽可能大。HeapMem使用用户提供的锁来锁定对内存的访问。详细信息请参见章节4.3,盖茨。

下面的示例创建一个大小为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(参见Gates一节对Gates的解释)来防止并发访问对HeapMem的空闲块列表进行操作的代码。HeapMem使用的Gate类型可以通过HeapMem的通用默认值进行静态配置

本例将HeapMem配置为使用GateMutexPri来保护代码的关键区域

var GateMutexPri = xdc.useModule('ti.sysbios.gates.GateMutexPri');
var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
HeapMem.common$.gate = GateMutexPri.create();

使用的门的类型取决于应用程序所需的保护级别。如果没有并发访问堆的风险,那么可以将“null”赋值为放弃使用任何Gate,这将提高性能。对于可能具有并发访问的应用程序,GateMutex是一个可能的选择。或者,如果关键线程可能与低优先级线程同时需要HeapMem,那么GateMutexPri将最适合于确保关键线程尽可能快地接收到对HeapMem的访问。参见4.3.2.2节,GateMutexPri了解更多信息。

7.8.3HeapBuf

HeapBuf用于分配固定大小的内存块,其设计具有快速和确定性。通常,程序需要创建和删除固定大小对象的不同数量的实例。HeapBuf是为这类对象分配空间的理想选择,因为它可以快速处理请求并且不会产生任何碎片。

当响应时间比有效的内存使用更重要时,HeapBuf也可以用于分配不同大小的对象。在这种情况下,HeapBuf将遭受“内部”碎片。总的来说,堆中永远不会有任何碎片空间,但是分配的块本身可能包含浪费的空间,因此碎片是分配块的“内部”。从HeapBuf分配和释放内存总是花费相同的时间,因此HeapBuf是一种“确定性”内存管理器。

下面的示例创建一个HeapBuf实例,它有10个大小为128的内存块。

第一个示例静态地配置堆。在本例中,不需要指定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参数。在指定这些运行时参数时要小心。块大小需要是最坏情况下结构对齐大小的倍数。bufSize应该等于blockSize * numBlocks。最坏情况下的结构对齐依赖于目标。在32位体系结构的设备上,使用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.4HeapMultiBuf

HeapMultiBuf旨在平衡HeapMem和HeapBuf的优势。在内部,HeapMultiBuf维护一个HeapBuf实例的集合,每个实例具有不同的块大小、对齐方式和块数量。HeapMultiBuf实例可以接受任何大小的内存请求,并简单地决定从哪个heapbuf中分配内存.

HeapMultiBuf在块大小方面提供了比单个HeapBuf更大的灵活性,但在很大程度上保留了HeapBuf的快速性能。HeapMultiBuf实例增加了循环遍历heapbuf以确定从哪个分配资源的开销。但是,在实践中,不同块大小的数量通常很小,并且总是一个固定的数字,因此HeapMultiBuf可以被某些定义视为确定性的。

HeapMultiBuf处理任何内存大小的请求,但总是返回固定大小的块之一。分配将不会返回关于分配块的实际大小的任何信息。当将一个块释放回HeapMultiBuf时,size参数将被忽略。HeapMultiBuf通过比较地址来确定要释放块的缓冲区。

当HeapMultiBuf用完其中一个缓冲区中的块时,可以配置它从下一个最大的缓冲区中分配块。这就是所谓的“块借”。有关HeapMultiBuf的更多信息,请参阅第1.6.1节中描述的在线参考。

下面的示例创建了一个HeapMultiBuf,它管理1024个mau的内存,这些内存被划分为3个缓冲区。它将管理8个大小为16 mau的区块,8个大小为32 mau的区块和5个大小为128 mau的区块,如下图所示。

第一个例子静态地配置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.5HeapTrack

HeapTrack是一个缓冲区管理模块,用于跟踪任何堆实例的所有当前分配的块。HeapTrack用于检测内存泄漏、缓冲区溢出和内存块的双重释放。任何XDCtools或SYSBIOS堆实例都可以插入到HeapTrack中。对于每个内存分配,将添加一个额外的数据包。运行时对象视图(ROV)使用这些数据来显示堆实例的信息。HeapTrack实现了默认的堆函数以及两个调试函数。第一个,HeapTrack_printHeap()打印给定HeapTrack实例的所有内存块。第二个,HeapTrack_printTask()打印给定Task句柄的所有内存块。

HeapTrack有几个检测关键内存错误的断言。这包括两次释放相同的内存块、溢出已分配的内存块、删除非空堆实例以及使用空堆对象调用HeapTrack_printHeap()。当使用HeapTrack时,会有性能和大小开销成本。在设置堆和缓冲区大小时,应该考虑到这些成本。

您可以在C代码中使用sizeof(HeapTrack_Tracker)来查找HeapTrack模块增加块大小的数量。这是当代码或其他函数从HeapTrack管理的堆调用Memory_alloc()时,内存大小增加的量。HeapTrack_Tracker结构被添加到分配块的末尾;因此,HeapTrack不会影响已分配块的对齐.

这个例子用一个现有的堆静态配置HeapTrack。

var HeapTrack = xdc.useModule('ti.sysbios.heaps.HeapTrack');
var heapTrackParams = new HeapTrack.Params();
heapTrackParams.heap = heapHandle;
Program.global.myHeap = HeapTrack.create(heapTrackParams);

还可以通过设置heapTrackEnabled配置参数,将HeapTrack与默认BIOS模块堆一起使用。

var BIOS = xdc.useModule('ti.sysbios.BIOS');
BIOS.heapTrackEnabled = true;

这个例子使用C代码动态地用一个现有的堆创建一个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");
}

  • 39
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值