Your app creashes because you have a try..finally construct in which you Free the memorystream cache immediately after creating and loading it.
Don't free the memorystream there - you haven't even used it yet.
You do need to destroy the memory streams you create, but not until the end of your program. Before that you will want to access those streams!
So include an OnDestroy handler for your form something like
procedure TForm1.FormDestroy(Sender: TObject);
var
ms: TMemoryStream;
begin
for ms in cache do
ms.Free;
end;
Assume your image filenames were in an array (slightly less complicated than a grid). Then you want a FillCache() routine something like
SetLength(cache, ImageCount);
for i:=1 to ImageCount do begin
cache[i-1]:=TMemoryStream.Create;
cache[i-1].LoadFromFile(PictureFileNames[i]);
end;
Remember that your cache is indexed from 0 to ImageCount-1, and for you, ImageCount is StringGrid1.RowCount-1.