Исключение ESBWrapperAlive и случаи его появления

26 13

ESBWrapperAlive - это диагностическое исключение для определения мест неправильной работы со ссылками на объекты системы. Оно может сопровождаться генерацией наведенных исключений, например Access Violation.

В статье рассмотрим неcколько ситуаций, при которых возможно возникновение данного исключения.

Неправильный порядок очистки ссылок на связанные объекты

Например такой код на ISBL приведет к появлению "ESBWrapperAlive Враппер набора данных не уничтожен. Компонента: Пользователи, индекс набора данных: 1":

App = Application.CloneApplication
Reference = App.ReferencesFactory.ПОЛ.GetComponent
DetailDataSet = Reference.DetailDataSet(1)
Reference = App.ReferencesFactory.ГПЛ.GetComponent

Причина возникновения ошибки в том, что удерживается ссылка на детальный набор данных справочника ПОЛ (справочник "Пользователи") при том, что уже отпущена ссылка на сам справочник.

Способы исправления:

  • Использовать для справочника ГПЛ (справочник "Группы пользователей") другую переменную:
App = Application.CloneApplication
Reference = App.ReferencesFactory.ПОЛ.GetComponent
DetailDataSet = Reference.DetailDataSet(1)
Reference1 = App.ReferencesFactory.ГПЛ.GetComponent
  • сначала завершить все работы со справочником ПОЛ и очистить ссылки в порядке обратном их означиванию:
App = Application.CloneApplication
Reference = App.ReferencesFactory.ПОЛ.GetComponent
DetailDataSet = Reference.DetailDataSet(1)
...
DetailDataSet = nil
Reference = App.ReferencesFactory.ГПЛ.GetComponent

Особенности работы цикла foreach

Цикл foreach имеет неочевидную особенность: после выполнения переменная цикла сохраняет значение, присвоенное ей на последней итерации цикла. Эта особенность может приводить к появлению ошибок ESBWrapperAlive, если явно не выполняется очистка переменной цикла после завершения цикла.

Пример

Reference = References.ПОЛ.GetComponent
Reference.Open
Reference.OpenRecord
DetailDataSet = Reference.DetailDataSet(1)
foreach DataSetLine in DetailDataSet
  ...
endforeach
Reference = nil

Неочевидная логика работы с объектами

Сюда относятся ситуации, которые на первый взгляд могут показаться дефектами, но на самом деле так сделано специально.

Рассмотрим пример:

Query = CreateQuery()
Query.CommandText = 'select * from XIni'
Query.Open
Field1 = Query.Fields('ValuePar')
...
Query.Close
Query.Open

Этот код приведет к генерации исключения "ESBWrapperAlive Внутренний объект поля TSBStringField не уничтожен". Дело в том, что поля запроса пересоздаются при его открытии. Чтобы избежать ошибок необходимо очищать ссылки на поля до повторного закрытия запроса:

Query = CreateQuery()
Query.CommandText = 'select * from XIni'
Query.Open
Field1 = Query.Fields('ValuePar')
...
Query.Close
Field1 = nil
Query.Open
26
Авторизуйтесь, чтобы оценить материал.
1
Андрей Девятьяров

По поводу  "если явно не выполняется очистка переменной цикла после завершения цикла":

Судя по тексту примера переменная цикла это DataSetLine, а очищается только Reference - поэтому непонятно, это правильный пример или нет.

Андрей Воронин

Не соглашусь с пунктом "Особенности работы цикла foreach" У меня была такая история:

ds3=doc.Detaildataset(3)
forEach rec in ds3
	rec.Requisites…..
endForeach
rec=nil
ds3=nil

и все это провоцировало как раз ESBWrapperAlive со всеми вытекающими

Пришлось поменять на While, все стало работать как надо

ds3=doc.Detaildataset(3)
While not ds3.eof
	ds3.Requisites…..
	ds3.next
EndWhile
ds3=nil

С тех пор, только whilesmiley

Андрей Куров
С тех пор, только while

while в работе с коллекциями выглядит однозначно хуже. Кроме того, он провоцирует ошибку с забытым .Next

А почему в примере

ds3=doc.Detaildataset(3)
forEach rec in ds3
	rec.Requisites…..
endForeach
rec=nil
ds3=nil

Нельзя было поменять местами последние две строки, вместо того, чтобы переделывать на while?

Андрей Воронин

Потому что как раз, если поменять местами, то это явный случай неправильной работы со ссылками - детальный набор данных уже отпустили,  а его запись держим.

Андрей Куров
Потому что как раз, если поменять местами, то это явный случай неправильной работы со ссылками - детальный набор данных уже отпустили,  а его запись держим.

А что означает "запись держим"? Вы же сначала обнулите ссылку на детальный набор данных, а потом на запись. Ничего держаться не будет.

Андрей Воронин

на строчке ds3=nil, в таком случае, вы и получите предупреждение ESBWrapperAlive, потому что в памяти еще осталась ссылка на запись, а на сам набор данных уже ссылки нет.
 

Андрей Куров

Т.е. если написать вот так:

ds3=doc.Detaildataset(3)
forEach rec in ds3
	rec.Requisites…..
endForeach
ds3=nil
rec=nil

то все равно будет ошибка ESBWrapperAlive?

Лев Кудряшов

Есть вопрос насчет исключения ESBWrapperAlive. Подключаю к типу карточки WebControl, там на javascript открывается набор данных dataset(1) и набор данных избранных. Все переменные обновляются, но ошибка все равно возникает о том, что набор данных не уничтожен, что и вызывает Access Violation. Знаете ли, в чем эта причина и как это исправить?

Лев Кудряшов: обновлено 01.03.2017 в 09:08
Петр Федотов

Лев, а в логах билдера что? 

Лев Кудряшов

Петр, получаю следующее сообщение в логе:

01.03.2017    13:48:42.004    Main(4180)    DIRECTUM    dbo    Debug    ESBWrapperAlive    Враппер набора данных не уничтожен. Компонента: Избранные исполнители, индекс набора данных: 1. <- SBQuery.TSBCustomDataSet.Destroy (2698) <- SBDS.TSBDataSet.Destroy (2577) <- System.TObject.Free (15655) <- System.Classes.TComponent.Destroy (15698) <- Db.TDataSet <- SBDS.TSBDataSet.Destroy (2577) <- System.TObject.Free (15655) <- SBQuery.TSBCustomDataSetWrapper.Destroy (7021) <- SBDS.TSBDataSetWrapper.Destroy (8859) <- System.TInterfacedObject._Release (36476) <- System.@IntfClear (35702) <- SBRef.TSBReferenceWrapper.Destroy (325) <- System.TObject.Free (15655) <- Olectrls.TOleControl.DefaultHandler <- Controls.TWinControl.WMDestroy <- Controls.TWinControl.WndProc <- Olectrls.TOleControl.WndProc <- Controls.TWinControl.MainWndProc <- System.Classes.StdWndProc (17059) <- Forms.TCustomForm.DestroyWindowHandle <- Forms.TCustomForm <- SBVistaFm.TSBVistaForm.Destroy (229) <- SBLocalizeControls.TSBLocalizeForm.Destroy (1464) <- SBScaledFm.TSBScaledForm.Destroy (124) <- dxRibbonForm.TdxCustomRibbonForm.Destroy (452) <- SBShortCutHandler.TSBShortCutHandledForm.Destroy (1289) <- SBFunctionHelpFm.TSBFunctionHelpForm.Destroy (415) <- System.TObject.Free (15655) <- Controls.TControl.WndProc <- Controls.TWinControl.WndProc <- Forms.TCustomForm.WndProc <- SBVistaFm.TSBVistaForm.WndProc (364) <- dxRibbonForm.TdxCustomRibbonForm.WndProc (2106) <- cxControls.TcxWindowProcLinkedObject.DefaultProc (8404) <- dxShadowWindow.TdxShadowWindow.OwnerWindowWndProc (334) <- cxControls.TcxWindowProcLinkedObjectList.WndProc (8516) <- Controls.TWinControl.MainWndProc <- System.Classes.StdWndProc (17059) <- Forms.TApplication.ProcessMessage <- Forms.TApplication.HandleMessage <- SBShortCutHandler.TSBShortCutHandledForm.ShowModal (1876) <- SBFm.TSBCustomForm.ShowModal (1169) <- SBFm.TSBCustomForm.PrepareAndShow (1554) <- SBFm.TSBCustomForm.InternalShow (1419) <- SBFm.TSBCustomForm.Show (1578) <- SBFm.TSBCustomFormWrapper.Show (849) <- SBISBLDevFunc.EditDataSetEventTexts (1611) <- SBInter.TSBInter.CalculateFunction (5810) <- SBInter.TSBInter.ExecuteFunction (2927) <- SBInter.TSBInter.ExecuteTermExprn (2409) <- SBInter.TSBInter.ExecuteScript (2983) <- SBInter.TSBInter.ExecutePrepared (5468) <- SBInter.TSBInter.Execute (5428) <- SBInter.TSBInter.Execute (5360) <- SBDataSetComp.TSBDataSetComponentWrapper.ExecuteISBLActionHandler (745) <- SBView.TSBCustomViewWrapper.ButtonsActionISBLHandler (5001) <- SBView.TSBCustomViewWrapper.ExecuteHandler (2787) <- System.Classes.TBasicAction.Execute (16558) <- Actnlist.TCustomAction.Execute <- SLStandardAction.TSLStandardAction.Execute (1071) <- System.Classes.TBasicActionLink.Execute (16469) <- dxBar.TdxBarItem.DoClick (20726) <- dxBar.TdxBarItem.DirectClick (20712) <- dxBar.TdxBarItemControl.ControlUnclick (39042) <- dxBar.TdxBarButtonControl.ControlUnclick (41167) <- dxBar.TCustomdxBarControl.DoLButtonUp (22022) <- dxBar.TdxBarControl.DoLButtonUp (51909) <- dxBar.TCustomdxBarControl.WMLButtonUp (21329) <- dxBar.TdxBarDockedControl.WMLButtonUp (48569) <- Controls.TControl.WndProc <- Controls.TWinControl.WndProc <- dxBar.TCustomdxBarControl.WndProc (21681) <- dxBar.TdxBarControl.WndProc (52786) <- Controls.TWinControl.MainWndProc <- System.Classes.StdWndProc (17059) <- Forms.TApplication.ProcessMessage <- Forms.TApplication.HandleMessage <- SBRte.Finalization (66) <- SBQuery.TSBCustomDataSet.Destroy (2698) <- SBDS.TSBDataSet.Destroy (2577) <- System.TObject.Free (15655) <- System.Classes.TComponent.Destroy (15698) <- Db.TDataSet <- SBDS.TSBDataSet.Destroy (2577) <- System.TObject.Free (15655) <- SBQuery.TSBCustomDataSetWrapper.Destroy (7021) <- SBDS.TSBDataSetWrapper.Destroy (8859) <- System.TInterfacedObject._Release (36476) <- System.@IntfClear (35702) <- SBRef.TSBReferenceWrapper.Destroy (325) <- System.TObject.Free (15655) <- Olectrls.TOleControl.DefaultHandler <- Controls.TWinControl.WMDestroy <- Controls.TWinControl.WndProc <- Olectrls.TOleControl.WndProc <- Controls.TWinControl.MainWndProc <- System.Classes.StdWndProc (17059) <- Forms.TCustomForm.DestroyWindowHandle <- Forms.TCustomForm <- SBVistaFm.TSBVistaForm.Destroy (229) <- SBLocalizeControls.TSBLocalizeForm.Destroy (1464) <- SBScaledFm.TSBScaledForm.Destroy (124) <- dxRibbonForm.TdxCustomRibbonForm.Destroy (452) <- SBShortCutHandler.TSBShortCutHandledForm.Destroy (1289) <- SBFunctionHelpFm.TSBFunctionHelpForm.Destroy (415) <- System.TObject.Free (15655) <- Controls.TControl.WndProc <- Controls.TWinControl.WndProc <- Forms.TCustomForm.WndProc <- SBVistaFm.TSBVistaForm.WndProc (364) <- dxRibbonForm.TdxCustomRibbonForm.WndProc (2106) <- cxControls.TcxWindowProcLinkedObject.DefaultProc (8404) <- dxShadowWindow.TdxShadowWindow.OwnerWindowWndProc (334) <- cxControls.TcxWindowProcLinkedObjectList.WndProc (8516) <- Controls.TWinControl.MainWndProc <- System.Classes.StdWndProc (17059) <- Forms.TApplication.ProcessMessage <- Forms.TApplication.HandleMessage <- SBShortCutHandler.TSBShortCutHandledForm.ShowModal (1876) <- SBFm.TSBCustomForm.ShowModal (1169) <- SBFm.TSBCustomForm.PrepareAndShow (1554) <- SBFm.TSBCustomForm.InternalShow (1419) <- SBFm.TSBCustomForm.Show (1578) <- SBFm.TSBCustomFormWrapper.Show (849) <- SBISBLDevFunc.EditDataSetEventTexts (1611) <- SBInter.TSBInter.CalculateFunction (5810) <- SBInter.TSBInter.ExecuteFunction (2927) <- SBInter.TSBInter.ExecuteTermExprn (2409) <- SBInter.TSBInter.ExecuteScript (2983) <- SBInter.TSBInter.ExecutePrepared (5468) <- SBInter.TSBInter.Execute (5428) <- SBInter.TSBInter.Execute (5360) <- SBDataSetComp.TSBDataSetComponentWrapper.ExecuteISBLActionHandler (745) <- SBView.TSBCustomViewWrapper.ButtonsActionISBLHandler (5001) <- SBView.TSBCustomViewWrapper.ExecuteHandler (2787) <- System.Classes.TBasicAction.Execute (16558) <- Actnlist.TCustomAction.Execute <- SLStandardAction.TSLStandardAction.Execute (1071) <- System.Classes.TBasicActionLink.Execute (16469) <- dxBar.TdxBarItem.DoClick (20726) <- dxBar.TdxBarItem.DirectClick (20712) <- dxBar.TdxBarItemControl.ControlUnclick (39042) <- dxBar.TdxBarButtonControl.ControlUnclick (41167) <- dxBar.TCustomdxBarControl.DoLButtonUp (22022) <- dxBar.TdxBarControl.DoLButtonUp (51909) <- dxBar.TCustomdxBarControl.WMLButtonUp (21329) <- dxBar.TdxBarDockedControl.WMLButtonUp (48569) <- Controls.TControl.WndProc <- Controls.TWinControl.WndProc <- dxBar.TCustomdxBarControl.WndProc (21681) <- dxBar.TdxBarControl.WndProc (52786) <- Controls.TWinControl.MainWndProc <- System.Classes.StdWndProc (17059) <- Forms.TApplication.ProcessMessage <- Forms.TApplication.HandleMessage <- SBRte.Finalization (66)    SBRte.exe    7.15.0.3114    10236    RRCAssignments#ctReference    INTANT\lkudryashov    False
 

Лев Кудряшов: обновлено 01.03.2017 в 10:15
Лев Кудряшов: обновлено 01.03.2017 в 10:48
Петр Федотов

Можете еще описать что делает пользователь? Похоже нажимает какую то кнопку и потом идет работа с некой формой, а после этого все падает. 

Ну и да, надо полный код посмотреть 

Лев Кудряшов

Петр, пользователь просто открывает карточку поручения. При показе карточки срабатывает открытие html файла, в котором срабатывает javascript код. Он отображает список Избранных. В последствии чего срабатывает описанное выше исключение. Предоставляю код метода, который подгружает избранных: 

function loadPerformers() {
                var name = "GTTFavoritePerformers";
                var currentRef = window.external.Form.View.Component;
                currentRef.OpenRecord();
                var currentAuthor = currentRef.Requisites("Employee").Value
                
                var performersRef = currentRef.Application.ReferencesFactory.ReferenceFactory(name).GetComponent();
                performersRef.Open();
                var currentAuthorRef = performersRef.Locate("Employee", currentAuthor);
                var disableCheckbox = currentRef.Form.Controls.FindControl("STDBEllipsis3").ReadOnly;
                
                if(currentAuthorRef) {
                    performersRef.OpenRecord();
                    var container = document.getElementById('body');
                    var toggleAllCheckbox = document.createElement('input');
                    toggleAllCheckbox.type = "checkbox";
                    toggleAllCheckbox.name = "toggleAll";
                    toggleAllCheckbox.style.marginTop = "0px";
                    toggleAllCheckbox.style.paddingTop = "0px";
                    if(disableCheckbox) {
                        toggleAllCheckbox.disabled = true;
                    }
                    toggleAllCheckbox.id = "toggleAll";
                    toggleAllCheckbox.onclick = (function() {
                        return function () {
                            toggle(this);
                        };
                    })();

                    var label = document.createElement('label');
                    label.htmlFor = "toggleAll";
                    label.appendChild(document.createTextNode("Выбрать всех"));

                    container.appendChild(toggleAllCheckbox);
                    container.appendChild(label);
                    
                    var performersDDS = performersRef.DetailDataSet(1);
                    var count = 1;
                    while(!performersDDS.EOF) {
                        var container = document.getElementById('body');
                        var checkbox = document.createElement('input');
                        //var perfomerT = performersDDS.Requisites("PerformerT").Value;
                        checkbox.type = "checkbox";
                        checkbox.name = "user111";
                        if(disableCheckbox) {
                            checkbox.disabled = true;
                        }
                        checkbox.value = performersDDS.Requisites("PerformerT").Value;
                        checkbox.id = "user_" + count;
                        checkbox.onclick = (function() {
                            return function () {
                                setPerformer(this.id, this.value);
                            };
                        })();

                        var label = document.createElement('label');
                        label.htmlFor = "user_" + count;
                        label.appendChild(document.createTextNode(performersDDS.Requisites("AdditionT").DisplayText));
                        
                        var paragraph = document.createElement('br');

                        container.appendChild(paragraph);
                        container.appendChild(checkbox);
                        container.appendChild(label);
                        // increase counter
                        count++;
                        // fill global employees array
                        employees.push(performersDDS.Requisites("PerformerT").Value);
                        //alert(performersDDS.Requisites("PerformerT").Value);
                        //perfomerT = null;
                        performersDDS.Next();
                    }
                    performersDDS = null;    
             
                                    }
                performersRef.Close();
                performersRef = null;
                currentRef = null;
              
            }

Петр Федотов

хм, вроде бы нет никакого явного криминала, попробуйте эту штуку удалить performersRef.Close(); 

или еще мне вот эта строка не нравится var performersRef = currentRef.Application.ReferencesFactory.ReferenceFactory(name).GetComponent(); - можно было бы в одну точку разделить её и тоже обнулять, хотя в ошибке конечно явно указано на детальный раздел. 

можно еще попробовать вообще убрать обнуления, как ни странно, иногда это тоже помогает

Если воспроизводится стабильно, можете пакет разработки выложить, попробуем погонять у нас. 

 

Авторизуйтесь, чтобы написать комментарий