I figured it out. The issue was most likely with how I created the letters (namely during “Begin Routine” of the trial). Now, I am creating a placeholder for the letters once at the beginning of the experiment, like so
matrix_size = 4;
coordinates = [];
const startX = -0.125, startY = 0.125; // Upper-left corner
const endX = 0.125, endY = -0.125; // Bottom-right corner
const step = (endX - startX) / (matrix_size - 1); // Same step size for x and y
// Looping row-wise (y first, then x)
for (let y = 0; y < matrix_size; y++) {
for (let x = 0; x < matrix_size; x++) {
const posX = parseFloat((startX + x * step).toFixed(3));
const posY = parseFloat((startY - y * step).toFixed(3)); // Subtract to move downward
coordinates.push([posX, posY]);
}
}
color = Array(matrix_size**2).fill("white");
angle = Array(matrix_size**2).fill(0);
letter_array = Array(matrix_size**2).fill('A');
letters = [];
for (let i = 0; i < matrix_size**2; i++) {
let letter = new visual.TextStim({"win": psychoJS.window, "name": "letters", "text": letter_array[i], "font": "Arial", "pos": coordinates[i], "height": 0.025, "wrapWidth": null, "ori": angle[i], "color": color[i], "colorSpace": "rgb", "opacty": null, "languageStyle": "LTR", "size": 5, "depth": (- 1.0)});
letters.push(letter);
}
and then, in Begin Routine for the trial, I overwrite/update the letters object with the specifics that I need.
for (let i = 0; i < matrix_size**2; i++) {
angle[i] = getRandomAngle();
letter_array[i] = getRandomLetter();
color[i] = "white";
}
letter_array[L_Loc-1] = "L"
letter_array[T_Loc-1] = "T"
angle[L_Loc-1] = 0
angle[T_Loc-1] = 0
if (Speed === "fast"){
color[L_Loc-1] = "red"
color[T_Loc-1] = "red"
}
// Update existing objects instead of recreating them
for (let i = 0; i < matrix_size**2; i++) {
letters[i].setText(letter_array[i]);
letters[i].setColor(color[i]);
letters[i].setOri(angle[i]);
letters[i].setAutoDraw(1); // This will start drawing each letter
}
The relevant code that I had in the “Begin Routine” section before was the following:
letters = [];
for (let i = 0; i < matrix_size**2; i++) {
let letter = new visual.TextStim({"win": psychoJS.window, "name": "letters", "text": letter_array[i], "font": "Arial", "pos": coordinates[i], "height": 0.025, "wrapWidth": null, "ori": angle[i], "color": color[i], "colorSpace": "rgb", "opacity": null, "languageStyle": "LTR", "size": 5, "depth": (- 1.0)});
letters.push(letter);
}
And I think that it was the creation of new visual.TextStim
and potentially also using letters.push(letter)
in every trial that caused the memory leak.
Sorry for pasting all this code, but I think it might be helpful as a reference for others.
I also want to encourage the developers of the visual search demo task visual_search [PsychoPy] to implement an efficient way of coding this into their experiment as a scalable example for others to use.