vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
46.94k stars 8.24k forks source link

【memory leak】A memory leak occurred while I was using vue #11253

Closed allenye0909 closed 2 months ago

allenye0909 commented 3 months ago

Vue version

3.4.21

Link to minimal reproduction

none (stand-alone software)

Steps to reproduce

Snipaste_2024-06-30_17-22-12 Snipaste_2024-06-30_17-23-42 Snipaste_2024-06-30_17-24-21 Snipaste_2024-06-30_17-24-43

hooks/layout.ts

import {useTaskStore} from "@/stores/modules/task"

export default () => {
  const taskStore = useTaskStore()
  const layoutMap = {
    1: (layoutName: any) => {
      if (layoutName === "list") {
        return "state_1_list"
      }
      if (layoutName === "detail") {
        return "state_1_detail"
      }
    },
    2: (layoutName: any) => {
      if (layoutName === "list") {
        return "state_2_list"
      }
      if (layoutName === "detail") {
        return "state_2_detail"
      }
    },
    3: (layoutName: any) => {
      if (layoutName === "list") {
        return "state_3_list"
      }
      if (layoutName === "detail") {
        return "state_3_detail"
      }
    }
  }

  function getWid_Hei() {
    let width, height;
    if (window.innerWidth) {
      width = window.innerWidth;
      height = window.innerHeight;
    } else if (document.compatMode === "BackCompat") {
      width = document.body.clientWidth;
      height = document.body.clientHeight;
    } else {
      width = document.documentElement.clientWidth;
      height = document.documentElement.clientHeight;
    }
    return {
      width: width,
      height: height
    }
  }

  const getCellDetailRect = (state: number) => {
    // TODO 列表组件宽度修改后需要更新此处代码
    const taskListContainerWidthObj: any = {
      1: 470,
      2: 470,
      3: 4
    }
    // const taskListContainerWidth = document.querySelector("#taskListContainer")?.getBoundingClientRect().width || 0
    const drawContainerWidth = document.querySelector(".drawContainer")?.getBoundingClientRect().width || 0
    const TaskDetailCellTableWidth = document.querySelector("#TaskDetailCellTable")?.getBoundingClientRect().width || 0
    const paddingMarginWidth = 16 * 2 + 2 + 16 * 2 + 16
    const cw = getWid_Hei().width - taskListContainerWidthObj[state] - drawContainerWidth - TaskDetailCellTableWidth - paddingMarginWidth

    const taskDetailContainerHeight = document.querySelector(".taskDetailContainer")?.getBoundingClientRect().height || 0
    const paddingMarginHeight = 16 * 2
    const ch = taskDetailContainerHeight - paddingMarginHeight - 60
    // console.log(state, cw, ch, taskListContainerWidth, drawContainerWidth, TaskDetailCellTableWidth)
    return {
      height: ch,
      width: cw
    }
  }

  const getClassByState = (layoutName: string) => {
    return layoutMap[taskStore.currentLayoutState](layoutName)
  }

  const selectLayout = (dir: number) => {
    // debugger
    // console.log("当前", taskStore.currentLayoutState)
    if (taskStore.currentLayoutState === 1 && dir === 1) {
      taskStore.setCurrentLayoutState(2)
      if (taskStore.currentTaskModuleType === "Red") {
        taskStore.setCurrentCellToolState(3)
      }
    } else if (taskStore.currentLayoutState === 3 && dir === 1) {
      taskStore.setCurrentLayoutState(1)
      taskStore.setCurrentCellImageZoomState(taskStore.currentCellImageZoomState - 2)
    } else if (taskStore.currentLayoutState === 2 && dir === -1) {
      taskStore.setCurrentLayoutState(1)
    } else if (taskStore.currentLayoutState === 1 && dir === -1) {
      taskStore.setCurrentLayoutState(3)
      taskStore.setCurrentCellImageZoomState(taskStore.currentCellImageZoomState === 14 ? 14 : taskStore.currentCellImageZoomState + 2)
    }

  }
  return {
    getClassByState, selectLayout, getCellDetailRect
  }
}

What is expected?

Locate What causes memory leaks,WHY?High probability is the question I use!!

Who can save me

What is actually happening?

When I get a task, I cache the task list and task details using pinia,Switch tasks and cache different task details

System Info

"vue": "^3.4.21",
"vite": "^4.4.9",
"vitest": "^0.34.4",
"vue-tsc": "^1.8.11"
"pinia": "^2.1.6",

Any additional comments?

No response

allenye0909 commented 3 months ago

env:

image

liangqi2510 commented 3 months ago

blockStack?和我的情况有点类似。https://github.com/liangqi2510/vue-block-study 不知道能不能帮到你。

allenye0909 commented 3 months ago

感谢回复,@liangqi2510 是有点类似, @yyx990803 已经处理了,或者是我使用方式不正确,那应该怎么使用呢? image

https://github.com/vuejs/core/pull/3106#issuecomment-807584522

liangqi2510 commented 3 months ago

我觉得你的情况和我类似,是因为 blockStack 正常情况下,在每次渲染后应该是空的。我现在还不确定你和我遇到的相同的情况。我可以详细说一下我的情况,和我解决的方式。

我遇到的情况是,我在使用element-puls的table组件的自定义 col 的 slot。但我插槽部分内的模版是有问题的,特定情况下,会产生异常。但这个异常被这个插槽所在的渲染函数(table-column)捕获,使 vue 框架没有捕获这个异常(正常应该由vue框架进行处理参考)。渲染过程也继续执行,但blockStack没有正常被清空。

我清理掉了我模版部分的错误,内存泄漏就消失了。你可以在控制台,把遇到异常暂停和遇到未捕获的异常勾选上,进行调试,看看能不找到这类异常。

liangqi2510 commented 3 months ago

补充一个我的截图 image

allenye0909 commented 3 months ago

@liangqi2510 确实是类似。 “我清理掉了我模版部分的错误,内存泄漏就消失了”,方便贴一下修改的代码示例和修改后代码示例吗?

liangqi2510 commented 3 months ago

代码不太方便,可以举个例子 {{row.userData.name}} -> {{row?.userData?.name}}

yyx990803 commented 2 months ago

VUE_HMR_RUNTIME only exists in dev mode. Make sure to only report memory leaks that happen in production mode, and make sure to provide actual reproductions.

There's nothing we can do without reproductions.