Пишу 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-файл, с этим примером, открыть не через сервер, а полному пути в адресной строке, то утечки нет.
Я думаю что дело не VUEX, а в компонентах что на него подписаны. Скорее всего один из их складывает данные в локальную коллекцию или массив и после изменения хранилища не чистит их.
Попробуй отключить все подписки на изменения, компонент за компонентом пока не найдешь.
Как оказалось,проблема была во 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 ...) присвоение объектов делать после их глубокого копирования. После таких манипуляций, в дев-режиме, стала заметна работа сборщика мусора. В конечном счете, объем потребляемой памяти все равно растет, но стали заметны откаты. Что же касается прод-режима, то там стало все замечательно.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Как можно при помощи javascript заменить слово в тексте, не используя replace?
Подскажите, каким способом лучше сделать (скриншот) подобную диаграмму? Данные должны браться из базы данных и выводитьсяВидел примеры с использованием...
Как получить обработанные данные в виде структурированных данных (например массива)Дело в том, что эти данные необходимо обновлять в таблице,...