vega/react-vega

Reopen: memory leak for time-varying data

shenenya opened this issue · 0 comments

I found the memory leak happens again. I tried with only vega-embed, and these is not.

I reproduced the problem with ReactVegaLiteDemo as follows:

  1. install react-timeout to stories
  2. change ReactVegaLiteDemo.jsx to follows:
import React from "react";
import { action } from "@storybook/addon-actions";
import { Vega, createClassFromSpec } from "../../react-vega/src";
import ReactTimeout from "react-timeout";

const data1 = {
  myData: [
    { a: "A", b: 20 },
    { a: "B", b: 34 },
    { a: "C", b: 55 },
    { a: "D", b: 19 },
    { a: "E", b: 40 },
    { a: "F", b: 34 },
    { a: "G", b: 91 },
    { a: "H", b: 78 },
    { a: "I", b: 25 },
    { a: "A", b: 20 },
    { a: "B", b: 34 },
    { a: "C", b: 55 },
    { a: "D", b: 19 },
    { a: "E", b: 40 },
    { a: "F", b: 34 },
    { a: "G", b: 91 },
    { a: "H", b: 78 },
    { a: "I", b: 25 }
  ]
};

const data2 = {
  myData: [
    { a: "A", b: 28 },
    { a: "B", b: 55 },
    { a: "C", b: 43 },
    { a: "D", b: 91 },
    { a: "E", b: 81 },
    { a: "F", b: 53 },
    { a: "G", b: 19 },
    { a: "H", b: 87 },
    { a: "I", b: 52 }
  ]
};

const spec1 = {
  $schema: "https://vega.github.io/schema/vega-lite/v4.0.0-beta.10.json",
  data: { name: "myData" },
  description: "A simple bar chart with embedded data.",
  encoding: {
    x: { field: "a", type: "ordinal" },
    y: { field: "b", type: "quantitative" }
  },
  mark: "bar"
};

const spec2 = {
  data: { name: "myData" },
  description: "A simple bar chart with embedded data.",
  encoding: {
    x: { field: "b", type: "quantitative" },
    y: { field: "a", type: "ordinal" }
  },
  mark: "bar"
};

const BarChart = createClassFromSpec({ mode: "vega-lite", spec: spec1 });

const code1 = `<VegaLite data={this.state.data} spec={this.state.spec} />`;

const code2 = `const BarChart = ReactVegaLite.createClassFromLiteSpec(spec1);
<BarChart data={this.state.data} />`;

class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: data1,
      info: "",
      spec: spec1
    };

    this.handleHover = this.handleHover.bind(this);
    this.handleToggleSpec = this.handleToggleSpec.bind(this);
    this.handleUpdateData = this.handleUpdateData.bind(this);
    this.handlers = { hover: this.handleHover };
  }

  setTimer = () => {
    var timer = function() {
      this.handleUpdateData();
      this.handleToggleSpec();
      this.timerHandle = this.props.setTimeout(timer.bind(this), 1);
    };
    this.timerHandle = this.props.setTimeout(timer.bind(this), 1);
  };

  componentDidMount = () => {
    this.setTimer();
  };

  handleHover(...args) {
    action("hover", {
      limit: 5
    })(args);
    this.setState({
      info: JSON.stringify(args)
    });
  }

  handleToggleSpec() {
    const { spec } = this.state;
    action("toggle spec")(spec);
    if (spec === spec1) {
      this.setState({ spec: spec2 });
    } else {
      this.setState({ spec: spec1 });
    }
  }

  handleUpdateData() {
    const { data } = this.state;
    action("update data")(data);
    if (data === data1) {
      this.setState({ data: data2 });
    } else if (data === data2) {
      this.setState({ data: data1 });
    }
  }

  render() {
    const { data, spec, info } = this.state;

    return (
      <div>
        <div style={{ float: "right" }}>
          <iframe
            title="star"
            src="https://ghbtns.com/github-btn.html?user=vega&repo=react-vega&type=star&count=true"
            frameBorder="0"
            scrolling="0"
            width="100px"
            height="20px"
          />
        </div>
        <button type="button" onClick={this.handleToggleSpec}>
          Toggle Spec
        </button>
        <button type="button" onClick={this.handleUpdateData}>
          Update data
        </button>
        <h3>
          <code>&lt;VegaLite&gt;</code> React Component
        </h3>
        Will recompile when spec changes and update when data changes.
        <pre>{code1}</pre>
        <Vega data={data} spec={spec} />
        <h3>
          <code>ReactVegaLite.createClassFromLiteSpec()</code>
        </h3>
        Use the given spec to create a reusable component.
        <pre>{code2}</pre>
        <BarChart data={data} />
        {info}
      </div>
    );
  }
}

export default ReactTimeout(Demo);
  1. Check the system memory costs. You could find the memory used by browser keep increasing.

截屏2020-05-18 下午4 41 13

截屏2020-05-18 下午4 44 07