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

This library is a memory leak #264

Open
episage opened this issue Jan 5, 2023 · 6 comments
Open

This library is a memory leak #264

episage opened this issue Jan 5, 2023 · 6 comments

Comments

@episage
Copy link

episage commented Jan 5, 2023

When calling SMA or other indicators relying on LinkedList the LinkedList items never get garbage collected. This is due to the structure of LinkedList that always contains reference to the next and previous element.

In NodeJS you must remove reference to the unused items for them to be disposed by GC.

@episage
Copy link
Author

episage commented Jan 5, 2023

Also, SMA relies on approximate, running algorithm. It is efficient but the results will differ when compared to other software.

@quanxufeng
Copy link

When calling SMA or other indicators relying on LinkedList the LinkedList items never get garbage collected. This is due to the structure of LinkedList that always contains reference to the next and previous element.

In NodeJS you must remove reference to the unused items for them to be disposed by GC.

so how can I solve this problem? could you please tell me How can I modify the code to fix it?

@denernun
Copy link

denernun commented Mar 28, 2023 via email

@episage
Copy link
Author

episage commented Mar 28, 2023

@quanxufeng

To solve this problem, you can create a custom LinkedList class that has built-in garbage collection support. This class will automatically remove references to unused items, allowing them to be properly disposed of by the garbage collector. Here's an example implementation:

class GCLinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }

  append(value) {
    const newNode = { value, prev: null, next: null };

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      newNode.prev = this.tail;
      this.tail.next = newNode;
      this.tail = newNode;
    }

    this.length++;
    return this;
  }

  remove(value) {
    let currentNode = this.head;

    while (currentNode) {
      if (currentNode.value === value) {
        if (currentNode.prev) {
          currentNode.prev.next = currentNode.next;
        } else {
          this.head = currentNode.next;
        }

        if (currentNode.next) {
          currentNode.next.prev = currentNode.prev;
        } else {
          this.tail = currentNode.prev;
        }

        currentNode.prev = null;
        currentNode.next = null;

        this.length--;
        return currentNode.value;
      }

      currentNode = currentNode.next;
    }

    return null;
  }

  removeFirst() {
    if (!this.head) {
      return null;
    }

    const removedNode = this.head;
    this.head = removedNode.next;

    if (this.head) {
      this.head.prev = null;
    } else {
      this.tail = null;
    }

    removedNode.next = null;
    this.length--;

    return removedNode.value;
  }

  removeLast() {
    if (!this.tail) {
      return null;
    }

    const removedNode = this.tail;
    this.tail = removedNode.prev;

    if (this.tail) {
      this.tail.next = null;
    } else {
      this.head = null;
    }

    removedNode.prev = null;
    this.length--;

    return removedNode.value;
  }
}

Now, you can use this custom LinkedList class to store your SMA or other indicator values. Whenever you no longer need a value, call the remove or removeFirst method, depending on your use case, to remove it from the list. This will ensure that the garbage collector disposes of the unused items properly.

For example:

const smaList = new GCLinkedList();

// Add new SMA values
smaList.append(smaValue);

// Remove old SMA values when no longer needed
smaList.removeFirst();

By managing your LinkedList items this way, you can ensure that unused items are correctly garbage collected, preventing memory leaks and improving your application's performance.

@quanxufeng
Copy link

@quanxufeng

To solve this problem, you can create a custom LinkedList class that has built-in garbage collection support. This class will automatically remove references to unused items, allowing them to be properly disposed of by the garbage collector. Here's an example implementation:

class GCLinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }

  append(value) {
    const newNode = { value, prev: null, next: null };

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      newNode.prev = this.tail;
      this.tail.next = newNode;
      this.tail = newNode;
    }

    this.length++;
    return this;
  }

  remove(value) {
    let currentNode = this.head;

    while (currentNode) {
      if (currentNode.value === value) {
        if (currentNode.prev) {
          currentNode.prev.next = currentNode.next;
        } else {
          this.head = currentNode.next;
        }

        if (currentNode.next) {
          currentNode.next.prev = currentNode.prev;
        } else {
          this.tail = currentNode.prev;
        }

        currentNode.prev = null;
        currentNode.next = null;

        this.length--;
        return currentNode.value;
      }

      currentNode = currentNode.next;
    }

    return null;
  }

  removeFirst() {
    if (!this.head) {
      return null;
    }

    const removedNode = this.head;
    this.head = removedNode.next;

    if (this.head) {
      this.head.prev = null;
    } else {
      this.tail = null;
    }

    removedNode.next = null;
    this.length--;

    return removedNode.value;
  }

  removeLast() {
    if (!this.tail) {
      return null;
    }

    const removedNode = this.tail;
    this.tail = removedNode.prev;

    if (this.tail) {
      this.tail.next = null;
    } else {
      this.head = null;
    }

    removedNode.prev = null;
    this.length--;

    return removedNode.value;
  }
}

Now, you can use this custom LinkedList class to store your SMA or other indicator values. Whenever you no longer need a value, call the remove or removeFirst method, depending on your use case, to remove it from the list. This will ensure that the garbage collector disposes of the unused items properly.

For example:

const smaList = new GCLinkedList();

// Add new SMA values
smaList.append(smaValue);

// Remove old SMA values when no longer needed
smaList.removeFirst();

By managing your LinkedList items this way, you can ensure that unused items are correctly garbage collected, preventing memory leaks and improving your application's performance.

Hi, episage, thanks for your reply, is there a method or a way that I can directly remove values or empty the list? can I access to the reference of the values list in this library?

@episage
Copy link
Author

episage commented Mar 28, 2023

Yes, you can add a method to the custom GCLinkedList class to clear the list and remove all references to the values. Here's the updated class with the new clear method:

class GCLinkedList {
  // ... (previous code)

  clear() {
    let currentNode = this.head;

    while (currentNode) {
      let nextNode = currentNode.next;
      currentNode.prev = null;
      currentNode.next = null;
      currentNode = nextNode;
    }

    this.head = null;
    this.tail = null;
    this.length = 0;
  }
}

This clear method iterates through the list, removing references to the prev and next nodes, effectively clearing the list. After calling this method, the garbage collector will be able to dispose of the unused items properly. To use the clear method, simply call it on your GCLinkedList instance:

const smaList = new GCLinkedList();

// Add new SMA values
smaList.append(smaValue);

// Clear the list and remove all references
smaList.clear();

Regarding direct access to the values list, the custom GCLinkedList class does not store the values in a separate list or array, as it uses a linked list structure with nodes referencing each other. However, you can create a method to retrieve all values as an array:

class GCLinkedList {
  // ... (previous code)

  getValues() {
    const values = [];
    let currentNode = this.head;

    while (currentNode) {
      values.push(currentNode.value);
      currentNode = currentNode.next;
    }

    return values;
  }
}

Now you can access the list values as an array:

const smaList = new GCLinkedList();

// Add new SMA values
smaList.append(smaValue);

// Get the values as an array
const valuesArray = smaList.getValues();
console.log(valuesArray);

This will output an array containing the values of the nodes in the list.

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

3 participants