Closed wcldyx closed 4 years ago
Can anyone see it, can you help me
@LinusBorg Can you help me with this problem
Here we create a small vm to handle the computed property:
If the computed property references objects/state that persists your host component's lifecylce, it will lead to the memory leak.
So we should make sure to destroy this instance once the host component is destroyed:
vm.$on('hook:destroyed', () => computedHost.$destroy())
will test this later.
So a Little update on this:
This memory leak happens like this:
computed()
refs that have a dependency for this object in a component computed()
ref itself is garbage collected, but a Vue instance, created internally by computed()
stays in memory, causing a leak for each such computed()
that's being created and then disposed.To implement computed()
, we create a small new Vue()
instance and add the argument of computed()
as a computed property:
This is necessary to actually achieve the typical computed behaviour.
However, the means that:
Dep
of this reactive state.That means that the Dep
instance has a reference to this watcher, and the watcher has a reference to that Vue instance
As we can't track or be informed when a compute()
ref is being gargabe collected, we have to way to clean up this watcher and therefore, this reference
In #277, I thought that I could solve the problem by destroying the Vue instance when the component in which we created the computed()
unmounts.
But that means that this computed reference, if not being garbage collected, will stop working, event tough both thje computed ref instance and the reactive state is depends on still exist.
So I abandoned it.
Currently investigating, will report once I have something to write down.
is this OK ?
Thanks for helping out!
I think this will have a similar problem as my approach. Think of this scenerio:
import { reactive, computed } from '@vue/composition-api'
import store from '/.someReactiveObject'
export default defineComponent({
setup() {
const parentInterface = inject('someKyey')
const countPlusOne = computed(() => store.counter + 1)
parentInterface.passComputed(countPlusOne)
}
})
This is of course nonsensical, but it should be easy to imagine that we want to pass our computed property to the parent, or some totally different module that we imported, for example. One of the advantages of having computed refs is that we an pas them around, after all!
In such a case, your approach, as well as mine, would break the internal computation of countPlusOne
when the component is being destoryed, even though the computed ref is still referenced by the parent component somewhere, and likely expected to work as normal.
That's basically the reason that I dropped my initial idea.
any progress here? I meet the same problem.
So I checked this out again and compared what we did in vue-next. I learned that we basically chose to do what I initially wanted to do here as well: destroy the watcher (or as its called in vue-next internally: thee effect) on unmount
See:
So I think we can resurrect #277
Hello everyone, is this problem fixed, why not update it?
We will. Lots of things to do right now, please be patient.
Hi @LinusBorg, I might have some idea
we want to pass our computed property to the parent
How can we pass a computed to the parent? passComputed
seems not to be an API (sorry I am not that familiar with vue-next). Could you lead me to some code entry? I guess we can try to collect VMs that the computed attached to. And after all the VMs are destroyed, we could dispose the computed safely.
or some totally different module that we imported.
For persisted/global computed, we could suggest users define them outside of any instance. So the computed won't attach to any VM, then the problem never bothers.
const store = vueCompositionApi.reactive({
list: new Array(100000).fill('').map((_, index) => {
return {
index
}
})
})
+ const ls = vueCompositionApi.computed(() => store.list)
// 2.Use the global Shared reactive object in the "computed" function in the "Item" component
const Example = {
template: `<div>{{ls.length}}</div>`,
setup() {
return {
- ls: vueCompositionApi.computed(() => store.list)
+ ls
}
}
}
Keep clicking the toggle button, you will find that the memory keeps increasing and will not be destroyed.