Утечка памяти при использовании Vuex

74
16 марта 2022, 14:50

Пишу MMO RTS. На фронте использую Vue. С заданной периодичностью, с сервера, по WebSoket, прилетают обновленные данные. Естественно, данные помещаются во Vuex, за которым следят компоненты.

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

Ниже код демонстрирующий проблему: запустите, откройте консоль - вкладка Memory - и наблюдайте

const data = { 
  lvl: 0, 
  a: { 
    lvl: 1, 
    b: { 
      lvl: 2, 
      c: { 
        lvl: 3 
      } 
    } 
  } 
} 
const store = new Vuex.Store({ 
  state: { 
    count: 0, 
    data: [] 
  }, 
  mutations: { 
    increment(state) { 
      state.count++; 
    }, 
    set_data(state, payload) { 
      state.data = payload; 
    } 
  }, 
  actions: { 
    increment(context) { 
      setInterval(() => { 
        context.commit('increment'); 
        const newData = JSON.parse(JSON.stringify(data)); 
        context.commit('set_data', newData); 
      }, 500); 
    } 
  } 
}); 
 
var app = new Vue({ 
  store, 
  el: '#app', 
  template: ` 
  <div>{{count}}</div>`, 
  data() { 
    return { 
      count: 0, 
      d: window.performance.memory.totalJSHeapSize 
    }; 
  }, 
  created() { 
    this.$store.dispatch('increment'); 
  }, 
  watch: { 
    '$store.state.data': { 
      deep: true, 
      handler() { 
        this.count = this.$store.state.count; 
      } 
    } 
  } 
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.1/vue.js"></script> 
    <script src="https://unpkg.com/vuex@2.0.0"></script> 
    <div id="app"></div>

Новость для меня печальная). Четкого понимания, как решить проблему - пока нет.

UPD Обнаружился нюанс: если html-файл, с этим примером, открыть не через сервер, а полному пути в адресной строке, то утечки нет.

Answer 1

Я думаю что дело не VUEX, а в компонентах что на него подписаны. Скорее всего один из их складывает данные в локальную коллекцию или массив и после изменения хранилища не чистит их.

Попробуй отключить все подписки на изменения, компонент за компонентом пока не найдешь.

Answer 2

Как оказалось,проблема была во Vuex. Если подключить последнюю версию (3.1.2), то это убирает утечку в моем демо-примере.

const data = { 
  lvl: 0, 
  a: { 
    lvl: 1, 
    b: { 
      lvl: 2, 
      c: { 
        lvl: 3 
      } 
    } 
  } 
} 
const store = new Vuex.Store({ 
  state: { 
    count: 0, 
    data: [] 
  }, 
  mutations: { 
    increment(state) { 
      state.count++; 
    }, 
    set_data(state, payload) { 
      state.data = payload; 
    } 
  }, 
  actions: { 
    increment(context) { 
      setInterval(() => { 
        context.commit('increment'); 
        const newData = JSON.parse(JSON.stringify(data)); 
        context.commit('set_data', newData); 
      }, 500); 
    } 
  } 
}); 
 
var app = new Vue({ 
  store, 
  el: '#app', 
  template: ` 
  <div>{{count}}</div>`, 
  data() { 
    return { 
      count: 0, 
      d: window.performance.memory.totalJSHeapSize 
    }; 
  }, 
  created() { 
    this.$store.dispatch('increment'); 
  }, 
  watch: { 
    '$store.state.data': { 
      deep: true, 
      handler() { 
        this.count = this.$store.state.count; 
      } 
    } 
  } 
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.1/vue.js"></script> 
    <script src="https://unpkg.com/vuex"></script> 
    <div id="app"></div>

Но, к сожалению, в моем приложении утечка не исчезла. Но это уже другая история

Продолжение истории: В итоге, пришел к выводу, что утечка максимально себя проявляет в дев-режиме. Поэтому у меня 2 подозреваемых: сам vue/vuex и vue-dev-tools, при этом, после иследования срезов памяти, больше склоняюсь к vue-dex-tools. Т.к. утечка памяти, сама по себе "пахнет" не очень хорошо, я все равно постарался ее минимизировать. Для этого мне пришлось во всех "тонких местах" (watch, computed, store ...) присвоение объектов делать после их глубокого копирования. После таких манипуляций, в дев-режиме, стала заметна работа сборщика мусора. В конечном счете, объем потребляемой памяти все равно растет, но стали заметны откаты. Что же касается прод-режима, то там стало все замечательно.

READ ALSO
Замена слова без replace

Замена слова без replace

Как можно при помощи javascript заменить слово в тексте, не используя replace?

142
Диаграмма Ганта на web

Диаграмма Ганта на web

Подскажите, каким способом лучше сделать (скриншот) подобную диаграмму? Данные должны браться из базы данных и выводитьсяВидел примеры с использованием...

90
Получение ответа от обработчика формы, посланной AJAX, в виде переменных или массива

Получение ответа от обработчика формы, посланной AJAX, в виде переменных или массива

Как получить обработанные данные в виде структурированных данных (например массива)Дело в том, что эти данные необходимо обновлять в таблице,...

154