-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
GL.getNewId memory leak fix #18668
base: main
Are you sure you want to change the base?
GL.getNewId memory leak fix #18668
Conversation
This can save some memory if you do many allocations here, but it will also be slower as accessing objects is slower than arrays. I'd suggest looking at |
The first one we used is:
but there was a problem that the array remained in size with the peak number of objects. Then next step we tried using new Map:
but for some reason in the final js file was:
regardless, if we make changes with new Map() in the resulting file, After that, we had no choice in favor of slow objects Thanks for suggesting to try with HandleAllocator, I'll check if it can help us. |
We have a recently-added thing called HandleAllocator which may be what we want to use here: Line 3737 in 30ba0ae
We use it in a few other places where we need to map JS objects to unique IDs. |
(Oops, I see @kripken already suggested that). |
BTW, |
For |
``>
In javascript array is not classic memory array like c++ or other language its like a js object with array like api const value = { id: 0 }; for (let i = 0; i < 100000; i ++) { { { { Array get element 1.9424650073051453 From which I conclude that getting by index for an object and an array is almost the same, and an object is even faster |
Regardless of how we micro-optimize the HandleAllocator, I think the its best to switch to the existing HandleAllocator for this purpose. We can propose optimization to the handle allocator as a followup. IIRC the issue you are trying to solve here is more about avoiding running out of handles, and the current HandleAllocator should solve that. |
The main problem is that at the peak we have a large number of buffers, which then decreases to a small one, but at the same time a huge array full of zeros remains, which consumes memory, and the object solves this problem because it allows you to remove the element completely |
Also, we could not figure out how to use HandleAllocator in your templates Can you add a code example right in that file how to declare it correctly? And another question, maybe it's worth using a variable to store all such objects and not a lot like now? |
var GL = { i think need change to GL = { |
We tried using handleAllocator with the test above const arr = [];
const obj = {};
const map = new Map();
function handleAllocator() {
this.allocated = [];
this.freelist = [];
this.get = function(id) {
return this.allocated[id];
};
this.allocate = function(handle) {
let id;
if (this.freelist.length > 0) {
id = this.freelist.pop();
this.allocated[id] = handle;
} else {
id = this.allocated.length;
this.allocated.push(handle);
}
return id;
};
this.free = function(id) {
delete this.allocated[id];
this.freelist.push(id);
};
}
const allocator = new handleAllocator()
const value = { id: 0 };
for (let i = 0; i < 100000; i ++) {
arr[i] = value;
obj[i] = value;
map.set(i, obj);
allocator.allocate(value)
}
{
const s = performance.now()
for (let i = 0; i < 1000000; i ++) {
arr[1000];
}
console.log('Array get element', performance.now() - s);
}
{
const s = performance.now()
for (let i = 0; i < 1000000; i ++) {
obj[1000];
}
console.log('Object get element', performance.now() - s);
}
{
const s = performance.now()
for (let i = 0; i < 1000000; i ++) {
map.get(1000);
}
console.log('Map get element', performance.now() - s);
}
{
const s = performance.now()
for (let i = 0; i < 1000000; i ++) {
allocator.get(1000);
}
console.log('HandleAllocator get element', performance.now() - s);
} and get results: Array get element 1.2000000001862645 @sbc100 @kripken What do you think, perhaps the test is not indicative? Then what test will be indicative? As I noticed, you cannot insert objects created through the new operator into the macro instance.
I investigated how many changes it would take to move to handleAllocator, and that's hundreds of changes. An alternative would be to modify the getNewId function. Take the implementation of handleAllocator as an example and combine it with getNewId. What do you think about it? |
Unfortunately tests like these may not work as you expect: for (let i = 0; i < 1000000; i ++) {
obj[1000];
} First, the read from To measure this carefully you'd need to use the result of the read, and store it somewhere it can't be optimized away, stuff like that. |
@kripken Would it be nice if I change the pull request to use the handleAllocator? What is the best way to choose for optimization? |
I took a stab at converting to HandleAllocator here: #18874. Still needs some more work but that is that general direction I think, |
In the company we make an editor, and therefore there is a need to create a lot of buffers at runtime.
This fix is used to remove the memory leak, since the current implementation on the array increases it indefinitely.
cloud.opendesign.com