Инструменты пользователя

Инструменты сайта


ob:o7:memory

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
ob:o7:memory [2018/11/30 01:13]
127.0.0.1 внешнее изменение
ob:o7:memory [2019/10/27 09:44] (текущий)
иван_денисов
Строка 1: Строка 1:
-====== ​Особенности работы с памятью ======+====== ​Работа с динамической памятью ======
  
 При выполнении команды **O7ARMv{6,​7}Linker.Link** в рабочий журнал будет выведено,​ сколько полученная программа потребляет ROM и RAM. Например,​ для программы из [[ob:​o7:​stm32f103|первого урока]] требуется 880 байт ROM и 16 байт RAM. При выполнении команды **O7ARMv{6,​7}Linker.Link** в рабочий журнал будет выведено,​ сколько полученная программа потребляет ROM и RAM. Например,​ для программы из [[ob:​o7:​stm32f103|первого урока]] требуется 880 байт ROM и 16 байт RAM.
Строка 9: Строка 9:
   * таблица указателей,​ строки,​ таблица модулей.   * таблица указателей,​ строки,​ таблица модулей.
  
-Куча используется только при динамическом выделении памяти через команду NEW, и она заполняется снизу вверх. Для сборки мусора в куче надо вызывать команду **MicroGC0.Collect**. Количество выделенной динамической памяти доступно в переменной **MicroKernel0.allocated**,​ начало кучи --- **MicroKernel0.heapOrg**,​ конец --- **MicroKernel0.heapLim**. Следовательно общий размер легко вычислить как их разность.+Куча используется только при динамическом выделении памяти через команду ​**NEW**, и она заполняется снизу вверх. Для сборки мусора в куче надо вызывать команду **MicroGC0.Collect**. Количество выделенной динамической памяти доступно в переменной **MicroKernel0.allocated**,​ начало кучи --- **MicroKernel0.heapOrg**,​ конец --- **MicroKernel0.heapLim**. Следовательно общий размер легко вычислить как их разность.
  
 Стек заполняет выделенную под него память сверху вниз. И когда этот объем полностью заполняется,​ он начинает расти поверх кучи. Поэтому большие переменные рекомендуется размещать либо глобально,​ либо в куче, выход за границы которой контролируется автоматически. При переполнении кучи указатель будет равен NIL после вызова NEW. Стек заполняет выделенную под него память сверху вниз. И когда этот объем полностью заполняется,​ он начинает расти поверх кучи. Поэтому большие переменные рекомендуется размещать либо глобально,​ либо в куче, выход за границы которой контролируется автоматически. При переполнении кучи указатель будет равен NIL после вызова NEW.
Строка 24: Строка 24:
  
 Переполнение стека возможно обнаружить и более простым путем, сравнив **stkPos** с **MicroKernel0.heapLim**. Если он меньше,​ значит стек уже начал писаться в область памяти,​ выделенной для кучи. Так возможно добавить ASSERT для аварийной остановки в случае переполнения стека. Про обработку аварийных остановок читайте [[http://​obertone.ru/​ob/​o7/​debug|заметку про отладку]]. Переполнение стека возможно обнаружить и более простым путем, сравнив **stkPos** с **MicroKernel0.heapLim**. Если он меньше,​ значит стек уже начал писаться в область памяти,​ выделенной для кучи. Так возможно добавить ASSERT для аварийной остановки в случае переполнения стека. Про обработку аварийных остановок читайте [[http://​obertone.ru/​ob/​o7/​debug|заметку про отладку]].
 +
 +===== Тестирование сборщика мусора =====
 +
 +Александр Ширяев разработал модуль для тестирования сборщика мусора:​
 +
 +{{ :​ob:​o7:​testgc0.odc |}}
 +
 + MODULE TmpTestGC0;
 +
 + (*
 + Alexander Shiryaev, 2019.10
 +
 + Dynamic memory (and garbage collection) test
 +
 + Board: Nucleo-F446RE
 + PA2: UART TX
 + PA3: UART RX
 + PA5: LED
 + *)
 +
 + IMPORT
 + SYSTEM,
 + ARMv7M := MicroARMv7M,​
 + Traps := MicroARMv7MTraps,​
 + Kernel := MicroKernel0,​
 + GC := MicroGC0,
 + TPorts := MicroSTM32F4TPorts,​
 + Pins := MicroSTM32F4Pins,​
 + Sys := MicroSTM32F405System,​
 + SysTick0 := DplaARMv7MSTM32SysTick0,​
 + WWDG := MicroARMv7MSTM32F4WWDG;​
 +
 + CONST
 + enableLED = TRUE;
 +
 + led0PinPort = Pins.A;
 + led0PinN = 5;
 + led0BSRR = Pins.GPIOABSRR;​
 +
 + freq0 = 128; (* Hz *)
 +
 + TYPE
 + Operation = POINTER TO OperationDesc;​
 + OperationDesc = RECORD
 + END;
 + Repeat = POINTER TO RepeatDesc;
 + RepeatDesc = RECORD (OperationDesc)
 + value: INTEGER
 + END;
 + End = POINTER TO EndDesc;
 + EndDesc = RECORD (OperationDesc)
 + END;
 +
 + VAR
 + cnt0: INTEGER;
 + operations:​ ARRAY 100 OF Operation;
 + nOp: INTEGER;
 + port: TPorts.Port;​
 +
 + PROCEDURE LEDOn;
 + BEGIN
 + SYSTEM.PUT(led0BSRR,​ {led0PinN})
 + END LEDOn;
 +
 + PROCEDURE LEDOff;
 + BEGIN
 + SYSTEM.PUT(led0BSRR,​ {led0PinN+16})
 + END LEDOff;
 +
 + PROCEDURE InitOperations;​
 + VAR i: INTEGER;
 + BEGIN
 + i := 0;
 + WHILE i < LEN(operations) DO
 + operations[i] := NIL;
 + INC(i)
 + END;
 + GC.Collect;​
 + nOp := 0
 + END InitOperations;​
 +
 + PROCEDURE AddRepeat (val: INTEGER);
 + VAR repeat: Repeat;
 + BEGIN
 + repeat := NIL;
 + NEW(repeat);​
 + repeat.value := val;
 + operations[nOp] := repeat;
 + INC(nOp)
 + END AddRepeat;
 +
 + PROCEDURE AddEnd;
 + VAR end: Repeat;
 + BEGIN
 + end := NIL;
 + NEW(end);​
 + INC(nOp)
 + END AddEnd;
 +
 + PROCEDURE PopulateOperations;​
 + VAR i: INTEGER;
 + BEGIN
 + i := 0;
 + WHILE i < 10 DO
 + AddRepeat(i);​
 + INC(i)
 + END;
 + i := 0;
 + WHILE i < 5 DO
 + AddEnd;
 + INC(i)
 + END
 + END PopulateOperations;​
 +
 + PROCEDURE Receive (id: CHAR; a: ARRAY OF CHAR; len: INTEGER);
 + VAR ok: BOOLEAN;
 + i: INTEGER;
 + BEGIN
 + IF id = 20X (* communication test *) THEN
 + TPorts.Send(port,​ 21X, SYSTEM.ADR(a),​ len, ok)
 + ELSIF id = 22X (* clear dynamic memory *) THEN
 + IF len = 0 THEN
 + InitOperations;​
 + TPorts.Send(port,​ 23X, 0, 0, ok)
 + END
 + ELSIF id = 24X (* populate dynamic memory *) THEN
 + IF len = 0 THEN
 + PopulateOperations;​
 + TPorts.Send(port,​ 25X, 0, 0, ok)
 + END
 + ELSIF id = 26X (* Kernel.allocated query *) THEN
 + IF len = 0 THEN
 + TPorts.Send(port,​ 27X, SYSTEM.ADR(Kernel.allocated),​ 4, ok)
 + END
 + ELSIF id = 28X (* TRAP test *) THEN
 + IF len = 0 THEN
 + ASSERT(FALSE)
 + END
 + ELSIF id = 2AX (* hangup test *) THEN
 + IF len = 0 THEN
 + REPEAT UNTIL FALSE
 + END
 + ELSIF id = 2CX (* multiple clear/​populate calls *) THEN
 + IF len = 0 THEN
 + i := 1000;
 + REPEAT DEC(i);
 + InitOperations;​
 + PopulateOperations;​
 + WWDG.Update
 + UNTIL i = 0;
 + TPorts.Send(port,​ 2DX, 0, 0, ok)
 + END
 + END
 + END Receive;
 +
 + PROCEDURE OnFreq0;
 + BEGIN
 + IF enableLED THEN
 + (* LED blink *)
 + INC(cnt0);​
 + IF cnt0 MOD (freq0 DIV 4) = 0 THEN
 + LEDOn
 + ELSIF cnt0 MOD (freq0 DIV 4) = freq0 DIV 8 THEN
 + LEDOff
 + END
 + END;
 +
 + WWDG.Update (* reset watchdog timer *)
 + END OnFreq0;
 +
 + PROCEDURE MainLoop;
 + BEGIN
 + REPEAT
 + TPorts.Receive(port);​
 + IF SysTick0.OnTimer() THEN
 + OnFreq0
 + END;
 + ARMv7M.WFI
 + UNTIL FALSE
 + END MainLoop;
 +
 + PROCEDURE Init;
 + VAR ok: BOOLEAN;
 + i: INTEGER;
 +
 + PROCEDURE InitPort;
 + VAR p: TPorts.InitPar;​
 + BEGIN
 + p.n := TPorts.USART2;​
 + p.RXPinPort := Pins.A;
 + p.RXPinN := 3;
 + p.RXPinAF := Pins.AF7;
 + p.TXPinPort := Pins.A;
 + p.TXPinN := 2;
 + p.TXPinAF := Pins.AF7;
 + p.UCLK := Sys.PCLK1;
 + p.baud := 115200;
 + p.parity := TPorts.parityNone;​
 + p.receive := Receive;
 + p.version1 := 1;
 + TPorts.Init(port,​ p)
 + END InitPort;
 +
 + PROCEDURE InitLED;
 + BEGIN
 + Pins.Configure(led0PinPort,​ led0PinN,
 + Pins.output,​ Pins.pushPull,​ Pins.low, Pins.noPull,​ 0)
 + END InitLED;
 +
 + BEGIN
 + InitPort;​ (* initialize communication port *)
 + IF enableLED THEN
 + InitLED;​ LEDOff; cnt0 := 0 (* initialize LED and related logic *)
 + END;
 + WWDG.Init(WWDG.WDGTBMax,​ WWDG.WMax, WWDG.TMax); (* initialize watchdog timer *)
 + SysTick0.Init(Sys.HCLK,​ freq0); (* initialize periodic timer *)
 +
 + IF Traps.trapFlag THEN Traps.ClearTrapFlag;​
 + i := 3;
 + REPEAT DEC(i);
 + TPorts.Send(port,​ 0DEX, SYSTEM.ADR(Traps.trap),​ 9, ok)
 + UNTIL i = 0
 + ELSE
 + i := 3;
 + REPEAT DEC(i);
 + TPorts.Send(port,​ 0CBX, 0, 0, ok)
 + UNTIL i = 0
 + END
 + END Init;
 +
 + BEGIN
 + Init;
 + MainLoop
 + END TmpTestGC0.
 +
 + O7ARMv7MLinker.Link STM32F446RE TmpTestGC0
  
 ---- ----
  
 Автор заметки:​ [[http://​iadenisov.ru|И.А. Денисов]] Автор заметки:​ [[http://​iadenisov.ru|И.А. Денисов]]
ob/o7/memory.1543529596.txt.gz · Последние изменения: 2018/11/30 01:13 — 127.0.0.1