PDA

Просмотр полной версии : С0414: Не хвататет перманентной памяти



Paha1977
10.06.2026, 11:28
Добрый день

Перестало хватать перманентной памяти на ПЛК210-12. До этого все было нормально, все компилировалось и заливалось в контроллер. В проект добавились только несколько констант. И теперь ошибка С0414.
Хотя объем retain намного меньше 64 кбайт. Кнопки "очисить" и "очистить все" не помогают.

Евгений Кислов
10.06.2026, 11:35
Добрый день

Перестало хватать перманентной памяти на ПЛК210-12. До этого все было нормально, все компилировалось и заливалось в контроллер. В проект добавились только несколько констант. И теперь ошибка С0414.
Хотя объем retain намного меньше 64 кбайт. Кнопки "очисить" и "очистить все" не помогают.

Добрый день.
Выложите, пожалуйста, ссылку на проект, в котором проявляется эта проблема.

Paha1977
10.06.2026, 11:44
https://disk.360.yandex.ru/d/1HS4m4KJckReTw

Евгений Кислов
10.06.2026, 12:00
В реализации CODESYS - квалификатор RETAIN/PERSISTENT влияет на весь объект. Это справедливо и для вложенных объектов.
Конкретный пример: SV_SETTINGS помечен как RETAIN PERSISTENT ---> SOLENOID_VALVE тоже целиком размещается в RETAIN PERSISTENT ---> astGVS тоже целиком размещается в RETAIN PERSISTENT.

За счет этого эффекта объекты вашего проекта действительно довольно быстро заполнили всю энергонезависимую память и теперь не влезают в нее.

Paha1977
10.06.2026, 12:43
Почему тогда эти объекты не добавляются автоматически при использовании "Добавить все пути экземпляров" в Persistent Vars?
Если объявить SV_SETTINGS не как STRUCT RETAIN PERSISTENT, а как STRUCT PERSISTENT, то будет ли вся структура SOLENOID_VALVE и экземпляры astGVS попадать в MRAM?

Евгений Кислов
10.06.2026, 12:56
Почему тогда эти объекты не добавляются автоматически при использовании "Добавить все пути экземплятов" в Persistent Vars?

Потому что подразумевается, что в контексте Persistent Vars они вас не интересуют.
Вообще, в типовом сценарии использования Persistent Vars рассматривается как отдельный глобальный список всех PERSISTENT-переменных проекта, в котором они вручную объявляются пользователем.
То, что можно указать квалификатор PERSISTENT где-то еще и потом использовать команду "Добавить все пути экземпляров" - это довольно сомнительное, на мой взгляд, поведение, уходящее корнями в какие-то древние версии среды.
Оно только вносит больше путаницы и вдвое увеличивает количество используемой энергонезависимой памяти.
Даже официальная документация рекомендует не использовать эту команду:

89489

Paha1977
10.06.2026, 13:02
То есть выход только один, разделять структуры на обычные и retain и обявлять экземпляры retain отдельно?

Paha1977
10.06.2026, 13:08
Потому что подразумевается, что в контексте Persistent Vars они вас не интересуют.
Вообще, в типовом сценарии использования Persistent Vars рассматривается как отдельный глобальный список всех PERSISTENT-переменных проекта, в котором они вручную объявляются пользователем.
То, что можно указать квалификатор PERSISTENT где-то еще и потом использовать команду "Добавить все пути экземпляров" - это довольно сомнительное, на мой взгляд, поведение, уходящее корнями в какие-то древние версии среды.
Оно только вносит больше путаницы и вдвое увеличивает количество используемой энергонезависимой памяти.
Даже официальная документация рекомендует не использовать эту команду:

89489

Но оно работает по крайне мере. Теперь все компилируется без ошибок и предупреждениий.

Евгений Кислов
10.06.2026, 13:25
То есть выход только один, разделять структуры на обычные и retain и обявлять экземпляры retain отдельно?

Да, на мой взгляд - это самый разумный подход.
Объекты, которые требуется использовать как PERSISTENT - объявлять в списке PersistentVars.
Объекты, которые требуется использоваться как RETAIN - объявлять в области VAR_RETAIN программ или GVL.

Емельянов Кирилл
12.06.2026, 03:52
То есть выход только один, разделять структуры на обычные и retain и обявлять экземпляры retain отдельно?

Лично я объявляю структуру. Если в этой структуре нужен персистэнт, то в персистэнт листе объявляется переменная нужного типа, а в структуре объявляется ссылка на этот персистэнт. Красота

Paha1977
17.06.2026, 08:15
Сделал в структурах, которые не RETAIN/PERSISTENT указатели REFERENCE на соответствующие структуры RETAIN/PERSISTENT.
Но почему-то, все равно уходит 58892 байт (90 %) энергонезависимой памяти. Хотя там их от силы 4 кБ должно быть.
С чем это связано?
Если структуры STRUCT RETAIN/END_STRUCT переопределить как STRUCT RETAIN PERSISTENT/END_STRUCT, то при компиляции память уменьшается до 56400 байт (86 %).

Валенок
17.06.2026, 08:51
Обычный указатель как?

Paha1977
17.06.2026, 10:04
Обычный указатель как?

Имеете ввиду POINTER?

Вот, например тот же:

TYPE SOLENOID_VALVE : //соленодный клапан
STRUCT
wsTitle : WSTRING;
xRun : BOOL; //команда открыть/закрыть э/м клапана
xWork : BOOL; //ответ э/м клапана "открыт/закрыт"
xLocal : BOOL; //местный
xBlock : BOOL; //блокировка
xAlarm : BOOL; //авария клапана
fbModeControl : MODE_CONTROL;
ptRetain : REFERENCE TO SV_SETTINGS;
// Визуализация
sVisuPictureID : STRING := 'SolenoidValveCloseNC';
END_STRUCT
END_TYPE

К нему идет вот такая ptRetain:

TYPE SV_SETTINGS : //энергонезависимые уставки
STRUCT RETAIN PERSISTENT
rTimeMaxOpen : REAL := 3; //максимальное время открытия, сек
rTimeMaxClose : REAL := 3; //максимальное время закрытия, сек
usiMode : USINT := 0; //режим (0-ручной, 1-авто, 2-наладочный)
eNormalState : NORMAL_STATE := NORMAL_STATE.NC; //нормальное состояние (0-NC, 1-NO)
END_STRUCT
END_TYPE

Экземпляры:

astGVS : ARRAY[c_iStartNumGVS..c_iEndNumGVS] OF SOLENOID_VALVE; //клапана соленоидные
astGVS_Ret : ARRAY[c_iStartNumGVS..c_iEndNumGVS] OF SV_SETTINGS; //клапана соленоидные

В инициализации добавлена ссыылка:

astGVS[i].ptRetain REF= astGVS_Ret[i];

Sergey361
17.06.2026, 10:20
Зачем объявлять структуру RETAIN PERSISTENT? Нужно объявить простую структуру, а переменные этой структуры уже в области Retain

Paha1977
17.06.2026, 13:34
То есть вы предлагаете по выше приведенному примеру объявить

TYPE SV_SETTINGS : //энергонезависимые уставки
STRUCT
rTimeMaxOpen : REAL := 3; //максимальное время открытия, сек
rTimeMaxClose : REAL := 3; //максимальное время закрытия, сек
usiMode : USINT := 0; //режим (0-ручной, 1-авто, 2-наладочный)
eNormalState : NORMAL_STATE := NORMAL_STATE.NC; //нормальное состояние (0-NC, 1-NO)
END_STRUCT
END_TYPE

А потом прописать PersistentVars уже переменные экземпляров

VAR_GLOBAL PERSISTENT RETAIN
//Клапаны соленоидные
GV.astGVS_Ret[1].rTimeMaxOpen: REAL := 1;
GV.astGVS_Ret[1].rTimeMaxClose: REAL := 1;
GV.astGVS_Ret[1].usiMode: USINT := USINT#0;
GV.astGVS_Ret[1].eNormalState: NORMAL_STATE := NORMAL_STATE.NC;
//......и т.д.
END_VAR
???

Но тогда эти переменные станут плейсхолдерами.

Валенок
17.06.2026, 14:04
Имеете ввиду POINTER?

Да. Без всяких REFERENCE
С ними как?

Paha1977
17.06.2026, 15:38
А в чем различие? Это то же указатель. REF удобнее использовать не разыменовывая знаком ^.

Валенок
17.06.2026, 17:29
А в чем различие? Это то же указатель. REF удобнее использовать не разыменовывая знаком ^.
Проблема решена?

Sergey361
17.06.2026, 19:53
Почему не объявить массив astGVS_Ret в списке PersistentVars?

Емельянов Кирилл
18.06.2026, 02:11
Что конкретно не получается?
89591

________


89592

________


89593

Занимаемая энергонезависимая память во всех случаях одинаковая, массив строк на неё никак не влияет. Вы же этого хотели добиться?

Paha1977
18.06.2026, 09:30
Проблема решена?

Спасибо всем. Сегодня на объекте буду пробовать. Оно как вроде на ПК компилируется без ошибок и предупреждений, но на ПЛК не знаю как себя поведет. Могут быть исключения.

Валенок
18.06.2026, 23:45
ну и хорошо



В инициализации добавлена ссыылка:
Кстати с указателями можно спокойно инитить прям в объявлении

var
x : тип := (p := adr(кого-то));
с рефами мутно