2016-11-22 2 views
1

Я не уверен, как лучше всего структурировать мое веб-приложение Vaadin.Лучшая практика создания больших веб-приложений с несколькими видами, многими компонентами и проблемами с nemory

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

Я вижу две возможности:

  1. Создать и инициализировать все объекты сразу в конструкторе вида. Когда вызывается View's enter(ViewChangeEvent event), привяжите данные к уже существующим объектам.

  2. Ничего не делать в конструкторе View. Создайте все компоненты в методе enter(ViewChangeEvent event), привяжите данные к этим компонентам.

упрощенный пример двух различных подходов:

общественный класс ONEView расширяет VerticalLayout реализует View {

private TextField[] textfields = new TextField[VaadinprojectUI.TESTLIMIT]; 

public OneView() { 
    long startMs = Calendar.getInstance().getTimeInMillis(); 
    for (int i=0;i<VaadinprojectUI.TESTLIMIT;i++){ 
     TextField txtField = new TextField("Textfield #" + i); 
     textfields[i] = txtField; 
     addComponent(txtField); 
    } 
    long finishMs = Calendar.getInstance().getTimeInMillis(); 
    System.out.println("OneView() - constructor" + (finishMs - startMs)); 
} 

@Override 
public void enter(ViewChangeEvent event) { 
    long startMs = Calendar.getInstance().getTimeInMillis(); 
    for (int i=0;i<VaadinprojectUI.TESTLIMIT;i++){ 
     textfields[i].setValue((String.valueOf(Math.random()*1000))); 
    } 
    long finishMs = Calendar.getInstance().getTimeInMillis(); 
    System.out.println("OneView - enter()" + (finishMs - startMs)); 
} 

ONEView будет сначала создать 1000 TextFields, добавить их к VerticalLayout, и хранить их в массиве для повторного использования. Когда OneView будет перемещен, он привяжет данные к текстовым полям.

public class TwoView extends VerticalLayout implements View{ 

    public TwoView() { 
     //nothing in the constructor 
    } 

    @Override 
    public void enter(ViewChangeEvent event) { 
     long startMs = Calendar.getInstance().getTimeInMillis(); 
     //entire load is in the "enter", only called upon navigation. 
     for (int i=0;i<VaadinprojectUI.TESTLIMIT;i++){ 
      TextField txtField = new TextField("Textfield #" + i); 
      txtField.setValue((String.valueOf(Math.random()*1000))); 
      addComponent(txtField); 
     } 
     long finishMs = Calendar.getInstance().getTimeInMillis(); 
     System.out.println("TwoView - enter()" + (finishMs - startMs)); 
    } 

TwoView ничего не будет делать в конструкторе, но всякий раз, когда он на навигацию, это создаст 1000 TextFields, и связать данные с ними. Текстовые поля не сохраняются и будут переделаны в другое время.

Некоторые испытания, навигации вперед и назад:

OneView() - constructor32 
OneView - enter()14 
TwoView - enter()28 
OneView - enter()5 
TwoView - enter()18 
OneView - enter()3 
TwoView - enter()12 

При запуске приложения ONEView требуется некоторое время, чтобы создать его TextFields. Но после этого он всегда выполняет более быструю работу по привязке данных к своим текстовым полям (что ожидается).

Вопросы:

  • Какие компромиссы с использованием системы ONEView, когда дело доходит до управления памятью? Можем ли мы свободно создавать View after View в больших приложениях? У меня есть приложение Vaadin реального мира, в котором мы получаем OutOfMemoryErrors, и я чувствую, что это потому, что я оставляю столько места для многоразовых компонентов.

  • Что происходит, когда страница остается? В TwoView я предполагаю, что Garbage Collection уничтожает все и освобождает память. В OneView текстовые поля остаются в памяти с данными, назначенными им. Есть ли что-то как событие «exit()», когда пользователь оставляет представление, которое мы должны использовать для очистки данных в компонентах? Я думаю в случаях ComboBoxes или таблиц с большим количеством объектов в них, но они не очищаются после выхода страницы и забивают память, потому что они не получат GC'd?

Спасибо за любые советы

+0

Вы сделали и проанализировали кучу кучи из своего приложения Vaadin реального мира, в котором есть проблемы с памятью? Вы должны уметь видеть, где используется большая часть памяти. Было бы интересно посмотреть, сколько памяти потребляет каждая пользовательская сессия. –

ответ

2

Я думаю, что это один из вопросов, которые лучше всего отвечали: Это зависит от ...

Когда вы предварительно создать все возможные элементы Vaadin, а затем свяжите/отвяжите их на View enter/leave, вы получите лучшую производительность.

С точки зрения памяти, он может получить уродливый, когда у вас есть 1000 экземпляров зрения «предустановленные», но и активно используется только 4-5 ...

Однако, если вы повторно использовать те же компоненты, вида/много раз, это будет лучше с точки зрения памяти GC.

Лучшим способом было бы создать элементы по мере необходимости, и удалить/освободить их как можно скорее.

Когда вы окончательно удаляете все ссылки на компоненты vaadin, GC должен запускаться до того, как будет выбрано исключение OOM.

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

+0

Я уже экспериментировал и понял, что есть объекты, которые я хотел бы (или ожидал, что GC позаботится), о которых не заботятся. Например, таблица в представлении, что я заполняю сложными объектами - когда пользователь переходит от полной таблицы, элементы все еще существуют. Поскольку таблица все еще существует, и она все еще находится на VerticalLayout, которая является частью представления. Я чувствую, что класс View пропускает метод «exit()» или «leave()», который я мог бы переопределить, в котором я мог бы вызвать removeAllItems(), чтобы позволить этим сложным объектам быть собранным мусором. – arnehehe

+1

. Навигатор запускает просмотр. Измените события до/после навигации. изменения. https://vaadin.com/api/7.7.0/com/vaadin/navigator/Navigator.html#addViewChangeListener-com.vaadin.navigator.ViewChangeListener- –

1

При добавлении вид в навигаторе можно либо добавить класс, который вы создали, как это:

Navigator navigator = new Navigator(this, this); 
navigator.addView("viewStuff", new ViewStuff()); 

Или вы может добавить вид и отсылают класс вместо

navigator.addView("viewStuff", ViewStuff.class); 

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

Смежные вопросы