[Cause]
i found the logic in toVue3ComponentInstance function
it use a WeakMap to cache to the map of Vue2 instance to fake-Vue3 instance
But the fake-Vue3 instance has a property named proxy that references to the Vue2 instance.
This proxy forms a strong reference, which prevent Vue2 instance to be GC,
And If the Vue2 instance is not GC, then the weakmap mapping will not be automatically deleted,
then the fake-vue3 instance will keep by the WeakMap obj, also the strong reference to vue2 instance will be keep too
This is the result of the Memlab memory leak test
[Affect]
All instances created after Vue-composition-API registration
[Solution]
there are to way to fix it;
replace all strong reference of vue2 instance with WeakRef
function toVue3ComponentInstance(vm) {
if (instanceMapCache.has(vm)) {
console.info('get vm from cache');
return instanceMapCache.get(vm);
}
// use WeakRef to reference vue2 instance
let weakRef = new WeakRef(vm);
const vmProxy = {
get proxy() {
return weakRef.deref() || {};
},
set proxy(val) {
const vm = weakRef.deref() || {};
const newVal = { ...vm, ...val };
weakRef = new WeakRef(newVal);
}
}.proxy;
var instance = {
proxy: vmProxy,
update: vmProxy.$forceUpdate,
type: vmProxy.$options,
uid: vmProxy._uid,
// $emit is defined on prototype and it expected to be bound
emit: vmProxy.$emit.bind(vmProxy),
parent: null,
root: null, // to be immediately set
};
bindCurrentScopeToVM(instance);
// map vm.$props =
var instanceProps = [
'data',
'props',
'attrs',
'refs',
'vnode',
'slots',
];
instanceProps.forEach(function(prop) {
proxy(instance, prop, {
get: function() {
return vmProxy['$'.concat(prop)];
},
});
});
proxy(instance, 'isMounted', {
get: function() {
// @ts-expect-error private api
return vmProxy._isMounted;
},
});
proxy(instance, 'isUnmounted', {
get: function() {
// @ts-expect-error private api
return vmProxy._isDestroyed;
},
});
proxy(instance, 'isDeactivated', {
get: function() {
// @ts-expect-error private api
return vmProxy._inactive;
},
});
proxy(instance, 'emitted', {
get: function() {
// @ts-expect-error private api
return vmProxy._events;
},
});
instanceMapCache.set(vm, instance);
vm.$on('hook:destroyed', function() { console.info('composition api cache has vm', instanceMapCache.has(vm)) });
if (vmProxy.$parent) {
instance.parent = toVue3ComponentInstance(vm.$parent);
}
if (vmProxy.$root) {
instance.root = toVue3ComponentInstance(vm.$root);
}
return instance;
}
delete the map manually
function toVue3ComponentInstance(vm) {
...
instanceMapCache.set(vm, instance);
// add this line
vm.$on('hook:destroyed', function() { instanceMapCache.delete(vm) });
...
}
The first method is not very elegant, so I recommend using the second method
[Other]
Since this library has stopped updating now,
I just fix it in my own project.
[Cause] i found the logic in toVue3ComponentInstance function it use a WeakMap to cache to the map of Vue2 instance to fake-Vue3 instance But the fake-Vue3 instance has a property named
proxy
that references to the Vue2 instance. Thisproxy
forms a strong reference, which prevent Vue2 instance to be GC, And If the Vue2 instance is not GC, then the weakmap mapping will not be automatically deleted, then the fake-vue3 instance will keep by the WeakMap obj, also the strong reference to vue2 instance will be keep tooThis is the result of the Memlab memory leak test
[Affect] All instances created after Vue-composition-API registration
[Solution] there are to way to fix it;
The first method is not very elegant, so I recommend using the second method
[Other] Since this library has stopped updating now, I just fix it in my own project.
hope this can help u if u meet the problem too.