npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

array-pool

v1.0.0

Published

Reduce garbage collection overhead by reusing array capacity

Downloads

5

Readme

array-pool

A simple and fast array pool implementation for avoiding allocations and garbage collection overhead.

Build Status Coverage Status

Installation

npm i --save array-pool

Usage

const ArrayPool = require('array-pool');

const arraysToAllocateInitially = 10;
const initialArrayCapacity = 50;
const pool = new ArrayPool(arraysToAllocateInitially, initialArrayCapacity);

// get an array from the pool
const array = pool.get();

// do something with the array
for (let i = 0; i < 100; i++) { array.push(i); }

// release the array back to the pool. IMPORTANT: THE ARRAY CAN NO LONGER BE SAFELY USED AFTER THIS POINT
pool.release(array);

// get the number of arrays the pool has allocated in total (including the ones in use)
console.log(pool.size());

Safety

The library has been designed to be as safe as possible to reduce the likelihood of bugs caused by using it, i.e. with most mistakes you just end up using more memory than you need to. For example, never releasing an array back to the pool is not an issue because the pool only retains a reference to the currently available arrays and thus the forgotten array would just be garbage collected normally.

However, like with any pooling implementation, use-after-free bugs are easy to introduce if you're not very careful:

// A WARNING EXAMPLE: DO NOT DO THIS
function printEverySecond(v) {
    console.log(v);
    setTimeout(() => printEverySecond(v));
}
const array = pool.get();
array.push(1, 2, 3);
printEverySecond(array);
// array will be emptied when released to the pool and will eventually be overwritten by some other piece of code
pool.release(array);

As a general rule of thumb, you should try to make sure the arrays from the pool never escape the scope of the function where they were fetched from the pool. If you pass the arrays to functions, you should make sure that the functions are either pure (BUT NEVER MEMOIZED) or at the very least stateless (i.e. perform mutation, but only to provided as arguments).

Performance considerations / tips

Just don't do it

Generally you'll want to avoid using this library (or pooling in general) as much as possible. If it's possible to solve the problem without pooling, it's probably best to do so.

Measure

You'll always want to measure before and after implementing pooling. Pooling is not a nitrous you can just add to get more performance; inappropriate use will be detrimental to the performance of your application and will quite possibly sky rocket your memory usage.

Avoid polymorphism

You should avoid using the same pool for different types of data. This will most likely cause the JIT to just abandon all hope of ever optimizing the usage of the arrays in the pool.

Avoid sharing pools for different purposes

You should try to keep the pools as specific to a certain task as possible. Different tasks often deal with different sizes of arrays and as the pool tracks the sizes of the arrays and adjusts automatically, you will end up with excess capacity for the tasks that don't require as much, needlessly increasing your memory usage. Sharing pools also easily leads to unintended polymorphism as a refactoring hazard.

Estimate your usage patterns

By default, the pool is completely dynamic and adjusts its allocation patterns based on usage. However, if you can correctly estimate the number of arrays needed in the pool and the maximum capacity needed for those arrays and pass them to the constructor, the pool will never have to allocate on the fly and you'll end up with more predictable performance characteristics.

Benchmarks

The repo includes an unfair (in favor of native, because the pool is not preallocated and is with varying types of data) micro-benchmark.

You can run the benchmarks yourself with ./scripts/benchmark. Here are the results on my computer (MacBook Pro (Retina, 13-inch, Early 2015), 3,1 GHz Intel Core i7, 16 GB 1867 MHz DDR3, node -v 9.5.0):

filterPooled median: 20.51587200164795ms average: 25.32200444266796ms min: 17.5102379322052ms max: 275.7377769947052ms
filterNative median: 24.807639002799988ms average: 28.991705557644366ms min: 22.115664958953857ms max: 170.6902370452881ms
arrayFromPooled median: 20.304154992103577ms average: 20.144703529405593ms min: 11.689600110054016ms max: 146.0108119249344ms
arrayFromNative median: 65.12847995758057ms average: 65.4233433881402ms min: 52.43484807014465ms max: 497.36474001407623ms

Lower is better.

License

ISC License. See the LICENSE file for more details.