Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

页面打开再关闭,内存不能释放 #2683

Open
lidc-01 opened this issue Oct 25, 2019 · 17 comments
Open

页面打开再关闭,内存不能释放 #2683

lidc-01 opened this issue Oct 25, 2019 · 17 comments

Comments

@lidc-01
Copy link

lidc-01 commented Oct 25, 2019

页面打开再关闭,内存不能释放

问题复现步骤

1.在左边菜单打开几个新的tab
2.关闭打开的tab
3.重复1和2
4.使用谷歌浏览器调试工具,会发现内存比初始打开页面时多占用了很多

格外信息

1.经本人测试,keep-alive的include动态变化时,就会出现这个内存泄漏的bug

@945005751
Copy link

这个问题我也发现,tab切换会导致内存增加无法释放,查了很多资料,目前原因不清楚,猜测是elementUI没有销毁吧

@PanJiaChen
Copy link
Owner

我看了下增长其实还好,有具体那个页面增长比较明显,或者能贴一下截图么?

@945005751
Copy link

我看了下增长其实还好,有具体那个页面增长比较明显,或者能贴一下截图么?

QQ截图20191025204403

第一张图的内存占用是在35M占用,页面黑色遮挡部分为商业数据,做了分页,一页是20条数据

  1. 已结排除数据过大table渲染占用内存可能(一页只有20条数据,列大约10列)
  2. 页面没有监听事件和复杂的组件渲染,简单时间组件和下拉选择

QQ截图20191025204558
c35b0.png)

第二张图的内存占用在93M
切换了多次tab(正常系统操作人员切换tab看数据正常,不存在我测试故意多次的情况)
返回任意路由后,回到该页面,内存并没有在我路由跳转后回收,反而因为我再次回到该页面而增加

最终占用93,但这并不是上限,多操作几次很容易120M以上奔跑

但浏览器在没有任何操作后,会回收一部分,达到在50M左右

而由于tab在同一页面的特性,切换tab依然会导致内存上涨

以上结果有一个对照:那就是将上述tab的页面换成二级路由菜单

换成路由菜单,切换路由很明显看见内存下降和回收,基本稳定在50M前后波动,渲染完后内存也下降

上述tab代码使用 keep-alive 缓存,但主页面没有缓存,也对比过相同把页面改成路由菜单,并开启缓存,内存占用和使用依然比tab低且回收快

根据以上实验初步得到结论:tab多个切换可能导致内存增长,无法释放,有内存泄漏的风险,猜测是elementUI的tab组件没有销毁占用内存

@lidc-01
Copy link
Author

lidc-01 commented Oct 25, 2019

我操作的是引导页和图标页,内存增长比较明显,而且关闭页面只回收一点点内存。
我感觉不是element-ui的问题,因为我测试过vue在用keep-alive包裹动态组件时,如果的include属性的值动态变化就会出现这种内存不回收的bug

@lidc-01
Copy link
Author

lidc-01 commented Oct 28, 2019

参考链接:vuejs/vue#9842
Memory leak when using "transition" and "keep-alive"

@MoHoChiao
Copy link

各位大哥, 請問此問題目前有解嗎?
目前小弟在專案中, 使用此框架完成客戶所有需求了
但最後也發現了這個問題, (事實上是細心一點的客戶發現的)
我在專案中建立的左選單有不少項, 所以可以打開數十個tab, 切換來切換去, 中間也可能按過重新整理, 反正就是不關閉瀏覽器的情況下, 瘋狂的測試使用, 然後最後.....關閉其它所有tab, 只留下一個tab來測試,
可以清楚發現, 即使只有一個tab, 但因為先前的使用, 讓記億體衝到1G以上, 且即使網頁都不再動它, 回收仍然十分的緩慢, 這個問題在IE特別更加明顥
不知道各位大大, 有沒有快速解決此問題的方法, 例如關閉element ui的transition效果, 或者菜單不使用keep-alive的方式呢

@zongwong
Copy link

各位大佬,这个问题解决了吗?我也遇到了,不知道如何解决

@ToMakeThings
Copy link

也遇见此类问题,并不知如何解决。经过多次测试,只要使用keep-alive 的include动态缓存页面,打开页面,在关闭。反复多次,内存会一直上升,并在快照里可以看见Array里面占用最多的就是我已经关闭的页面的data数据。如果会销毁组件,不应该会把data的数据也一并销毁了么?为什么会出现在快照里?

@tiandao-dongguan
Copy link

tiandao-dongguan commented May 28, 2020

相同的问题,重复的打开和关闭一个数据量大的页面,内存直接爆到了900M,浏览器直接崩溃了。

@Vcc1
Copy link

Vcc1 commented Aug 4, 2020

是的 我写了一个路由的缓存组件解决这个问题 你可以试下
将下面的代码段放入 命名为v-keep-alive.vue 放入项目中
`<script>
/**通过URL 缓存页面

日期:2020/8/4
/
var cache = Object.create(null);
var keys = [];
function remove(keys, key) {
if (keys && key) {
var index = keys.indexOf(key);
if (index != -1) {
keys.splice(index, 1);
}
}
}
/*
修剪缓存
/
function pruneCache(keepAliveInstance, filter) {
const { cache, keys, _vnode } = keepAliveInstance;
for (const key in cache) {
const cachedNode = cache[key];
if (cachedNode) {
if (!filter(key)) {
pruneCacheEntry(cache, key, keys, _vnode);
}
}
}
console.log("页面缓存数量:" + keys.length);
}
/*
修剪缓存入口
*/
function pruneCacheEntry(cache, key, keys, current) {
const cached = cache[key];
// 主动执行某个组件的destory,触发destroy钩子,达到销毁目的,然后移除缓存中的key-value
cached && cached.componentInstance.$destroy();
cache[key] = null;
remove(keys, key);
}
export default {
name: "v-keep-alive",

// 抽象组件
abstract: true,
props: {
keyArray: []
},
created() {
// 组件创建时创建缓存对象
this.cache = cache;
this.keys = keys;
},

destroyed() {
// 销毁时清除所有缓存
// for (const key in this.cache) {
// pruneCacheEntry(this.cache, key, this.keys);
// }
},

mounted() {
this.$watch("keyArray", val => {
//销毁不在key数组的对象
pruneCache(this, name => val.some(v => v == name));
});
},

render() {
const slot = this.$slots.default;
const vnode = slot[0];
const componentOptions = vnode && vnode.componentOptions;
this.$vnode.componentOptions.Ctor.options.abstract = true;
if (componentOptions) {
const { cache, keys } = this;
const key =
vnode.key.indexOf("__transition") == 0 ? vnode.data.key : vnode.key;

if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance;
remove(keys, key);
keys.push(key);
console.log("页面缓存数量:" + keys.length);
} else {
cache[key] = vnode;
keys.push(key);
console.log("页面缓存数量:" + keys.length);
}
vnode.data.keepAlive = true;
}
return vnode || (slot && slot[0]);
}
};
</script>然后打开/src/store/modules 目录 的tagsView文件 将所有name字符 替换为path 然后打开\src\views\layout\components 目录的AppMain.vue 引用v-keep-alive 组件 将原来的keep-alive替换为 v-keep-alive 使用组件

引用组件import vKeepAlive from "../../../components/V/v-keep-alive";注册组件 components: {
vKeepAlive
},`

操作完成后缓存和标签页是同步的 标签页关闭缓存删除 不知道怎么控制代码格式-。-

@wzch333
Copy link

wzch333 commented Dec 16, 2020

截止到今天 有没有可行的办法呀

@wzch333
Copy link

wzch333 commented Dec 30, 2020

是的 我写了一个路由的缓存组件解决这个问题 你可以试下
将下面的代码段放入 命名为v-keep-alive.vue 放入项目中
`<script>
/**通过URL 缓存页面

日期:2020/8/4
/
var cache = Object.create(null);
var keys = [];
function remove(keys, key) {
if (keys && key) {
var index = keys.indexOf(key);
if (index != -1) {
keys.splice(index, 1);
}
}
}
/*
修剪缓存
/
function pruneCache(keepAliveInstance, filter) {
const { cache, keys, _vnode } = keepAliveInstance;
for (const key in cache) {
const cachedNode = cache[key];
if (cachedNode) {
if (!filter(key)) {
pruneCacheEntry(cache, key, keys, _vnode);
}
}
}
console.log("页面缓存数量:" + keys.length);
}
/*
修剪缓存入口
*/
function pruneCacheEntry(cache, key, keys, current) {
const cached = cache[key];
// 主动执行某个组件的destory,触发destroy钩子,达到销毁目的,然后移除缓存中的key-value
cached && cached.componentInstance.$destroy();
cache[key] = null;
remove(keys, key);
}
export default {
name: "v-keep-alive",

// 抽象组件
abstract: true,
props: {
keyArray: []
},
created() {
// 组件创建时创建缓存对象
this.cache = cache;
this.keys = keys;
},

destroyed() {
// 销毁时清除所有缓存
// for (const key in this.cache) {
// pruneCacheEntry(this.cache, key, this.keys);
// }
},

mounted() {
this.$watch("keyArray", val => {
//销毁不在key数组的对象
pruneCache(this, name => val.some(v => v == name));
});
},

render() {
const slot = this.$slots.default;
const vnode = slot[0];
const componentOptions = vnode && vnode.componentOptions;
this.$vnode.componentOptions.Ctor.options.abstract = true;
if (componentOptions) {
const { cache, keys } = this;
const key =
vnode.key.indexOf("__transition") == 0 ? vnode.data.key : vnode.key;

if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance;
remove(keys, key);
keys.push(key);
console.log("页面缓存数量:" + keys.length);
} else {
cache[key] = vnode;
keys.push(key);
console.log("页面缓存数量:" + keys.length);
}
vnode.data.keepAlive = true;
}
return vnode || (slot && slot[0]);
}
};
</script>然后打开/src/store/modules 目录 的tagsView文件 将所有name字符 替换为path 然后打开\src\views\layout\components 目录的AppMain.vue 引用v-keep-alive 组件 将原来的keep-alive替换为 v-keep-alive 使用组件

引用组件import vKeepAlive from "../../../components/V/v-keep-alive";注册组件 components: {
vKeepAlive
},`

操作完成后缓存和标签页是同步的 标签页关闭缓存删除 不知道怎么控制代码格式-。-

keyArray是干嘛的... 而且关闭标签页 页面缓存怎么没减少

@wzch333
Copy link

wzch333 commented Jan 7, 2021

各位大哥, 請問此問題目前有解嗎?
目前小弟在專案中, 使用此框架完成客戶所有需求了
但最後也發現了這個問題, (事實上是細心一點的客戶發現的)
我在專案中建立的左選單有不少項, 所以可以打開數十個tab, 切換來切換去, 中間也可能按過重新整理, 反正就是不關閉瀏覽器的情況下, 瘋狂的測試使用, 然後最後.....關閉其它所有tab, 只留下一個tab來測試,
可以清楚發現, 即使只有一個tab, 但因為先前的使用, 讓記億體衝到1G以上, 且即使網頁都不再動它, 回收仍然十分的緩慢, 這個問題在IE特別更加明顥
不知道各位大大, 有沒有快速解決此問題的方法, 例如關閉element ui的transition效果, 或者菜單不使用keep-alive的方式呢

有什么好解决办法吗

@wzch333
Copy link

wzch333 commented Jan 7, 2021

相同的问题,重复的打开和关闭一个数据量大的页面,内存直接爆到了900M,浏览器直接崩溃了。

到现在有什么好到解决办法吗

@wzch333
Copy link

wzch333 commented Jan 7, 2021

也遇见此类问题,并不知如何解决。经过多次测试,只要使用keep-alive 的include动态缓存页面,打开页面,在关闭。反复多次,内存会一直上升,并在快照里可以看见Array里面占用最多的就是我已经关闭的页面的data数据。如果会销毁组件,不应该会把data的数据也一并销毁了么?为什么会出现在快照里?

到现在有什么好到解决办法吗

@Bain-liu
Copy link

同问,有什么办法解决吗

1 similar comment
@rool80
Copy link

rool80 commented Nov 30, 2022

同问,有什么办法解决吗

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests