hustcc / echarts-for-react

⛳️ Apache ECharts components for React wrapper. 一个简单的 Apache echarts 的 React 封装。
https://git.hust.cc/echarts-for-react
MIT License
4.51k stars 629 forks source link

Memory Leaks! #533

Open 0xAskar opened 1 year ago

0xAskar commented 1 year ago

The ReactEcharts library is causing memory leaks. During Dev mode, while I am on the same page and constantly refreshing after changes, in about a few hours, I get a javascript memory heap problem that kills my code. This is not good, as I'm unable to launch to production with the library in fear of it causing memory issues and killing my site.

With normal echarts, you have to call the dispose method. Please see article. I see in your source code that it does have the call in the unmount:

  componentWillUnmount() {
    this.dispose();
  }

But, it seems I still get this memory issue after staying on the same page and refreshing.

I am also tracking the the memory limits as below:

        console.log("jsHeapSizeLimit", abbreviateNumber(memory.jsHeapSizeLimit))
        console.log("totalJSHeapSize", abbreviateNumber(memory.totalJSHeapSize))
        console.log("usedJSHeapSize", abbreviateNumber(memory.usedJSHeapSize))

And it increases after each refresh

This is a problem for many people as well in the echarts community. Here's some with the issue as well. This is a crucial issue or else this library cannot be used in production! Here is my code below

import * as echarts from "echarts/core";
// import ReactEcharts from "echarts-for-react";
import ReactEChartsCore from "echarts-for-react/lib/core";
import {
  GridComponent,
  DatasetComponent,
  DataZoomComponent,
  TooltipComponent
} from "echarts/components";
import { ScatterChart, LineChart, BarChart } from "echarts/charts";
import { UniversalTransition } from "echarts/features";
import { CanvasRenderer } from "echarts/renderers";
import {useEffect, useState} from "react";
import Styles from "./depth.module.css";
import { GetCollectionDepth } from "../../../../lib/Listings/GetCollectionDepth";
export default function Depth(props) {
    echarts.use([
      DataZoomComponent,
      DatasetComponent,
      GridComponent,
      LineChart,
      ScatterChart,
      BarChart,
      CanvasRenderer,
      UniversalTransition,
      TooltipComponent
    ]);

    const [options, setTempOptions] = useState(null)
    const [depth_data, setDepthData] = useState(null)

    useEffect(async () => {
        if (props == null || props.contract_address == null) {return}
        console.log(props.contract_address)
        let results = await GetCollectionDepth(props.contract_address, 10, 1000, 0)
        setDepthData(results)
        let chart_data = results.chart
        let xs = []; let all_markets = results.all_markets
        chart_data.forEach((item) => {
            xs.push((item.x).toString() + "Ξ")
            let temp_markets = {}
            item.details.forEach((order) => {
                if (temp_markets[order.market] == null) { temp_markets[order.market] = 1 }
                else {temp_markets[order.market] += 1 }
            })
            for (let key in all_markets) {
               if (!(key in temp_markets)) { all_markets[key].push(0)}
               else { all_markets[key].push(temp_markets[key])}
            }
        })
        // create series
        let temp_options = {
            title: {
                text:"foo",
                subtext:"bar",
                x:'center',
                textStyle: {
                    color: "white"
                }
            },
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                // Use axis to trigger tooltip
                type: 'shadow' // 'shadow' as default; can also be 'line' or 'shadow'
              }
            },
            legend: {},
            grid: {
            //   left: '3%',
            //   right: '4%',
            //   bottom: '3%',
            //   containLabel: true
            },
            yAxis: {
              type: 'value'
            },
            xAxis: {
              type: 'category',
              data: xs
            },
            series: []
        };
        for (let key in all_markets) {
            let temp_series = {
                name: key,
                type: 'bar',
                stack: 'total',
                // label: {
                //     show: true
                // },
                emphasis: {
                    focus: 'series'
                },
                data: all_markets[key]
            }
            temp_options.series.push(temp_series)
        }
    setTempOptions(temp_options)
    },[props])
    return (
        <div className = {Styles.container}>
            {options != null ? <ReactEChartsCore
              echarts={echarts}
              option={options}
              style={{
                width: "100%",
                display: "flex",
                color: "white",
                height: "100%",
                flexDirection: "column",
                overflow: "scroll"
              }}
            /> : null}
        </div>
    )
}
Screen Shot 2023-03-09 at 9 54 14 PM Screen Shot 2023-03-09 at 9 53 08 PM
c-ctkd commented 1 year ago

i'm also having this exact same issue! it would be nice to have a way to dispose unused instances or at least give us a way to workaround it