Index: /trunk/psphot/src/psphotSourceMatch.c
===================================================================
--- /trunk/psphot/src/psphotSourceMatch.c	(revision 33586)
+++ /trunk/psphot/src/psphotSourceMatch.c	(revision 33587)
@@ -3,4 +3,8 @@
 bool psphotMatchSourcesAddMissing (pmConfig *config, const pmFPAview *view, const char *filerule, psArray *objects);
 bool psphotMatchSourcesSetIDs (psArray *objects);
+
+static psArray     *psphotMatchFootprintCacheAlloc (int nImages);
+static pmFootprint *psphotMatchLookupFootprint (psArray *cache, int footprintID, int imageID);
+static pmFootprint *psphotMatchCopyFootprint (psArray *cache, pmFootprint *footprint, int imageID, psImage *image, psArray *footprints);
  
 psArray *psphotMatchSources (pmConfig *config, const pmFPAview *view, const char *filerule) 
@@ -193,4 +197,5 @@
     // vector to track if source for an image is found
     psVector *found = psVectorAlloc(nImages, PS_TYPE_U8);
+    psArray *footprintCache = psphotMatchFootprintCacheAlloc(nImages);
 
     for (int i = 0; i < objects->n; i++) { 
@@ -219,5 +224,5 @@
 
 	// we make a copy of the largest footprint; this will be used for all new sources associated with this object
-	pmFootprint *footprint = NULL;
+	pmFootprint *largestFootprint = NULL;
 	if (iSpansMax != -1) { // copy the footprint info
 	    pmSource *src = obj->sources->data[iSpansMax]; 
@@ -226,6 +231,5 @@
 	    psAssert(src->peak->footprint->nspans == nSpansMax, "wrong footprint?");
 	    
-	    // we only care about the spans, do not worry about the image of this footprint
-	    footprint = pmFootprintCopyData(src->peak->footprint, NULL);
+            largestFootprint = src->peak->footprint;
 	}
 
@@ -248,11 +252,16 @@
 	    
 	    // assign to a footprint on this readout->image
-	    if (footprint) {
-		peak->footprint = pmFootprintCopyData(footprint, readout->image);
-
-		// the peak does not claim ownership of the footprint (it does not free it). save a copy of this 
-		// footprint on detections->footprints so we can free it later
-		psArrayAdd(detections->footprints, 100, peak->footprint); 
-		psFree (peak->footprint);
+	    if (largestFootprint) {
+                // we save the copies that we make of the of the footprints in a hash so that we can reuse them
+                // for all sources that share the fooprint. Without this we had serious memory explosion in
+                // dense fields with lots of footprints (spans are small but when you have enough of them ...)
+                peak->footprint = psphotMatchLookupFootprint(footprintCache, largestFootprint->id, index);
+                if (!peak->footprint) {
+                    // the peak does not claim ownership of the footprint (it does not free it). 
+                    // psphotMatchCopyFootprint saves a copy of this 
+                    // footprint on detections->footprints so we can free it later
+                    peak->footprint = psphotMatchCopyFootprint(footprintCache, largestFootprint,
+                                            index, readout->image, detections->footprints);
+                }
 	    }
 	    
@@ -272,4 +281,9 @@
 	    pmSourceDefinePixels (source, readout, source->peak->x, source->peak->y, OUTER);
 
+#if (0)
+            fprintf(stderr, "Add mising source for obj: %5d %5d image: %d flux: %f size: %4d %4d\n",
+                                                      i, obj->id, index, peakFlux, source->pixels->numRows, source->pixels->numCols);
+#endif
+
 	    peak->assigned = true;
 	    pmPhotObjAddSource(obj, source);
@@ -277,6 +291,6 @@
 	    psFree (source);
 	}
-	psFree (footprint);
-    }
+    }
+    psFree(footprintCache);
 
     // how many sources do we have now?
@@ -309,2 +323,54 @@
     return true;
 }
+
+// Cache of footprints created for unmatched sources.
+static psArray * psphotMatchFootprintCacheAlloc (int nImages) {
+    psArray *cache = psArrayAlloc(nImages);
+    for (int i = 0; i < nImages; i++) {
+        psHash *hash = psHashAlloc(5000);
+        cache->data[i] = hash;
+    }
+    return cache;
+}
+
+// Find copy of footprint with given ID made for a given image
+static pmFootprint *psphotMatchLookupFootprint (psArray *cache, int footprintID, int imageID) {
+    psHash *hash = (psHash *) cache->data[imageID];
+
+    psAssert(hash != NULL, "missing hash for image %d", imageID);
+
+    // footprintID is the id of the original footprint.
+    char key[32];
+    sprintf(key, "%d", footprintID); 
+
+    // The footprints in our hashes are the copies of that footprint for the respective images
+    pmFootprint *copy = psHashLookup(hash, key);
+
+    return copy;
+}
+
+// Create a copy of a given footprint for a given image
+static pmFootprint *psphotMatchCopyFootprint (psArray *cache, pmFootprint *footprint, int imageID, psImage *image, psArray *footprints) {
+
+    psAssert((imageID >= 0 && imageID < cache->n), "invalid imageID %d", imageID);
+
+    psHash *hash = (psHash *) cache->data[imageID];
+
+    psAssert(hash != NULL, "missing hash for image %d", imageID);
+
+    char key[32];
+    sprintf(key, "%d", footprint->id); 
+
+    pmFootprint *copy = pmFootprintCopyData (footprint, image);
+
+    // save a copy in this image's hash
+    psHashAdd(hash, key, copy);
+
+    // save a copy of this footprint on the passed in footprints Array so we can free it later
+    psArrayAdd(footprints, 100, copy);
+
+    // drop our ref
+    psFree(copy);
+
+    return copy;
+}
