Closed hari7696 closed 4 months ago
All our live demos are pure html, which provide minimal recipes without regard to your preferred framework (Angular, React, Vue). I used this live demo and used Chrome's memory monitor and the MacOS activity monitor to track memory as I opened each of the buttons (chris_MRA, chris_PD, ...) on the top toolbar, each which loads a different volume with a different resolution. While some volumes demand more resources than others, I did not see a regular increase in resource demands.
Note that this live demo code simply loads a new set of volume(s), without worrying about removing pre-existing volumes.
nv1.loadVolumes(volumeList1);
It is very hard to troubleshoot snippets of non-functional code, or when large frameworks are used. To create a minimal pure HTML project to showcase a problem, I would start a hot-reloadable instance of NiiVue:
git clone git@github.com:niivue/niivue.git
cd niivue
npm install
npm run dev
With this NiiVue instance loaded, edit the /niivue/src/index.html page to emulate the behavior that you find problematic.
@hari7696 , in your clean up code, you are referencing nv1
in the for loop, but all other niivue instances in your code snippet are referenced as nv2
. Is this a typo, or the source of your observed issue?
In addition, you may want to look into useContext
and createContext
with React. We use this in our NiiVue desktop app. Here is an example.
@hari7696 , please reopen if you can provide a minimal React demo showing the bad behaviour.
Hi @hanayik @neurolabusc
Thanks for the inputs, here is the standalone code that simulates the issue I am facing.
I hosted the code here : https://devmetavision3d.rc.ufl.edu/ in "dummy" tab
import React, { useState, useEffect } from 'react';
import { Niivue } from '@niivue/niivue';
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
function DummyRender() {
const [fileName, setSelectedFile] = useState("");
const [dropdownOpen, setDropdownOpen] = useState(false);
const [isattached , setIsAttached] = useState(false);
const nv1 = new Niivue();
const nv2 = new Niivue();
const files = ["5x_ADP.nii.gz","5x_AMP.nii.gz","5x_Aarachidonic.acid.nii.gz","5x_Alanine.nii.gz","5x_Ascorbic.Acid.nii.gz","5x_Aspartate.nii.gz","5x_Carnosine.nii.gz","5x_Citric.Acid.nii.gz","5x_Docosahexaenoic.acid.nii.gz","5x_Fructose.1.6.Bisphosphate.nii.gz","5x_G6P.nii.gz","5x_GMP.nii.gz","5x_GSH.nii.gz","5x_Glucose.nii.gz","5x_Glutamate.nii.gz","5x_Glutamine.nii.gz","5x_Glycerol.3.phosphate.nii.gz","5x_Glycerophosphorylethanolamine.nii.gz","5x_HEME.nii.gz","5x_Hypoxanthine.nii.gz","5x_IMP.nii.gz","5x_Inosine.nii.gz","5x_LPA..20.1..nii.gz","5x_LPA..20.4..nii.gz","5x_LPA..22.4..nii.gz","5x_LPA..22.6..nii.gz","5x_LPA.18.0..nii.gz","5x_LPA.18.1..nii.gz","5x_LPE..16.1..nii.gz"]
useEffect( () => {
nv1.attachTo('gl1');
nv2.attachTo('gl2');
setIsAttached(true);
}, [fileName]);
useEffect(() => {
console.log("Main func invoked")
if (isattached) {
console.log("volumes loading")
const volumeList1 = [
{
url: `https://devmetavision3d.rc.ufl.edu/data/Alzhemier/Disease/Inverted/${fileName}`,
opacity: 0.9,
visible: true,
colormap: 'blue2red',
}
];
nv1.loadVolumes(volumeList1);
nv1.updateGLVolume();
nv1.setSliceType(nv1.sliceTypeAxial);
nv2.loadVolumes(volumeList1);
nv2.updateGLVolume();
nv2.setSliceType(nv2.sliceTypeRender);
}
return () => {
for (let i = 0; i < nv1.volumes.length; i++) {
nv1.removeVolumeByIndex(i);
}
for (let i = 0; i < nv2.volumes.length; i++) {
nv2.removeVolumeByIndex(i);
}
setIsAttached(false);
console.log("Volumes removed");
};
}, [fileName]);
const toggleDropdown = () => setDropdownOpen(prevState => !prevState);
return (
<div className="container">
<div >
<Dropdown isOpen={dropdownOpen} toggle={toggleDropdown} style={{ textAlign: 'left', width: '300px', padding: '10px' }}>
<DropdownToggle caret style={{ width: '400px' }}>
{fileName || "Select a file"}
</DropdownToggle>
{/* The right prop is omitted or set to false for left alignment */}
<DropdownMenu className="scrollable-menu">
{files.map((file, index) => (
<DropdownItem
key={index}
onClick={() => setSelectedFile(file)}
>
{file}
</DropdownItem>
))}
</DropdownMenu>
</Dropdown>
</div>
<div className="row"><div className="col"><hr style={{ border: 'none', height: '2px', backgroundColor: 'black' }} /></div></div>
<div className="row">
<div className="col-1" style={{ fontSize: '24px', fontWeight: 'bold', marginRight: '14px' }}>Wild Type Brain</div>
<div id="demo1" className="col-5 p-2" style={{ height: '300px' }}>
<canvas id="gl1" style={{ width: '500px', height: '400px' }}></canvas>
</div>
<div id="demo1" className="col-5 p-2" style={{ height: '300px' }}>
<canvas id="gl2" style={{ width: '500px', height: '400px' }}></canvas>
</div>
</div>
</div>
);
}
export default DummyRender;
Behaviour observed.
@hari7696 , from what I can see, it looks like you have two useEffect statements that have the same dependency. In the past, this has caused issues in my other apps.
Also, your implementation seems to create a new Niivue instance on every re-render. I would suggest using useContext or useRef for the Niivue instances. I would also leave the Niivue instances attached to the canvas, and just use the Niivue removeVolume and loadVolumes methods to change the image you want rendered in the canvas.
Hi @hanayik
Thanks for the suggestion. Switching to useRef and leaving the instances attached solved my issue.
Hi
I am using niivue to display a 3d rendering, but the memory used by page is kept on increasing after every swtich to a new image. I believe I am not doing aproper unmount cleanup.
As a part of cleaning up, I am removing all volumes and updating the GLvolume, but looks like the earlier image arrays are still persisting in the memory. The images, I am fecthing are of a size of 100+ MB, so I clearly see the memory increase. I am no expert in WebGL and pretty new react. would apprecaite your inputs.
following is my unmount cleanup
partial roguh code I am using.