--- src/core/com/lowagie/text/pdf/GlyphList.java	2010-09-27 23:48:35.000000000 -0700
+++ src/core/com/lowagie/text/pdf/GlyphList.java	2010-10-25 21:22:40.000000000 -0700
@@ -57,8 +57,10 @@
 import com.lowagie.text.pdf.fonts.FontsResourceAnchor;
 
 public class GlyphList {
-    private static HashMap unicode2names = new HashMap();
-    private static HashMap names2unicode = new HashMap();
+
+    // Initial capacity based on runtime data
+    private static final HashMap unicode2names = new HashMap(7500);
+    private static final HashMap names2unicode = new HashMap(7500);
         
     static {
         InputStream is = null;
@@ -89,7 +91,8 @@
                 String hex = null;
                 if (!t2.hasMoreTokens())
                     continue;
-                name = t2.nextToken();
+                // intern these tokens to save memory
+                name = t2.nextToken().intern();
                 if (!t2.hasMoreTokens())
                     continue;
                 hex = t2.nextToken();
@@ -120,4 +123,4 @@
     public static String unicodeToName(int num) {
         return (String)unicode2names.get(new Integer(num));
     }
-}
\ No newline at end of file
+}
--- src/core/com/lowagie/text/pdf/PdfNumber.java	2010-09-27 23:48:35.000000000 -0700
+++ src/core/com/lowagie/text/pdf/PdfNumber.java	2010-09-28 00:36:26.000000000 -0700
@@ -153,8 +153,9 @@
     /**
      * Increments the value of the <CODE>PdfNumber</CODE>-object by 1.
      */
-    public void increment() {
-        value += 1.0;
-        setContent(ByteBuffer.formatDouble(value));
-    }
-}
\ No newline at end of file
+    // Remove this mutator method since we are caching these objects
+    //public void increment() {
+    //    value += 1.0;
+    //    setContent(ByteBuffer.formatDouble(value));
+    //}
+}
--- src/core/com/lowagie/text/pdf/PdfReader.java	2010-09-27 23:48:35.000000000 -0700
+++ src/core/com/lowagie/text/pdf/PdfReader.java	2010-10-25 21:22:40.000000000 -0700
@@ -65,6 +65,7 @@
 import java.util.Set;
 import java.util.zip.InflaterInputStream;
 import java.util.Stack;
+import java.util.concurrent.ConcurrentHashMap;
 import java.security.Key;
 import java.security.MessageDigest;
 import java.security.cert.Certificate;
@@ -143,6 +144,10 @@
      */
     private boolean appendable;
 
+    private static final Map pdfNumberMap = new ConcurrentHashMap();
+    private static final Map pdfNameMap = new ConcurrentHashMap();
+    private static final Map pdfStringMap = new ConcurrentHashMap();
+
     protected PdfReader() {
     }
 
@@ -825,7 +830,7 @@
                             obj = new PdfBoolean(((PdfBoolean)obj).booleanValue());
                             break;
                         case PdfObject.NAME:
-                            obj = new PdfName(obj.getBytes());
+                            obj = getPdfName(obj.getBytes());
                             break;
                     }
                     obj.setIndRef(ref);
@@ -871,7 +876,7 @@
                         obj = new PdfBoolean(((PdfBoolean)obj).booleanValue());
                         break;
                     case PdfObject.NAME:
-                        obj = new PdfName(obj.getBytes());
+                        obj = getPdfName(obj.getBytes());
                         break;
                 }
                 obj.setIndRef(ref);
@@ -1537,7 +1542,7 @@
                 break;
             if (tokens.getTokenType() != PRTokeniser.TK_NAME)
                 tokens.throwError("Dictionary key is not a name.");
-            PdfName name = new PdfName(tokens.getStringValue(), false);
+            PdfName name = getPdfName(tokens.getStringValue(), false);
             PdfObject obj = readPRObject();
             int type = obj.type();
             if (-type == PRTokeniser.TK_END_DIC)
@@ -1612,11 +1617,9 @@
                 return arr;
             }
             case PRTokeniser.TK_NUMBER:
-                return new PdfNumber(tokens.getStringValue());
+                return getPdfNumber(tokens.getStringValue());
             case PRTokeniser.TK_STRING:
-                PdfString str = new PdfString(tokens.getStringValue(), null).setHexWriting(tokens.isHexString());
-                // crypto handling
-                str.setObjNum(objNum, objGen);
+                PdfString str = getPdfString(tokens, objNum, objGen);
                 if (strings != null)
                     strings.add(str);
 
@@ -1627,7 +1630,7 @@
                     return cachedName;
                 } else {
                     // an indirect name (how odd...), or a non-standard one
-                    return new PdfName(tokens.getStringValue(), false);
+                    return getPdfName(tokens.getStringValue(), false);
                 }
             }
             case PRTokeniser.TK_REF:
@@ -1658,6 +1661,58 @@
         }
     }
 
+    private static PdfNumber getPdfNumber(String n) {
+        PdfNumber num = (PdfNumber)pdfNumberMap.get(n);
+        if (num == null) {
+            num = new PdfNumber(n);
+            pdfNumberMap.put(n, num);
+        }
+        return num;
+    }
+
+    private static PdfNumber getPdfNumber(int n) {
+        String s = String.valueOf(n);
+        return getPdfNumber(s);
+    }
+
+    private static PdfName getPdfName(String n) {
+        return getPdfName(n, true);
+    }
+
+    private static PdfName getPdfName(String n, boolean checkLength) {
+        PdfName name = (PdfName)pdfNameMap.get(n);
+        if (name == null) {
+            name = new PdfName(n, checkLength);
+            pdfNameMap.put(n, name);
+        }
+        return name;
+    }
+
+    private static PdfName getPdfName(byte[] b) {
+        String s = new String(b);
+        PdfName name = (PdfName)pdfNameMap.get(s);
+        if (name == null) {
+            name = new PdfName(b);
+            pdfNameMap.put(s, name);
+        }
+        return name;
+    }
+
+    private static PdfString getPdfString(PRTokeniser tokens, int objNum, int objGen) {
+        String key = tokens.getStringValue();
+
+        PdfString str = (PdfString)pdfStringMap.get(key);
+        if (str == null) {
+            str = new PdfString(tokens.getStringValue(), null);
+            str = str.setHexWriting(tokens.isHexString());
+            // crypto handling
+            str.setObjNum(objNum, objGen);
+
+            pdfStringMap.put(key, str);
+        }
+        return str;
+    }
+
     /** Decodes a stream that has the FlateDecode filter.
      * @param in the input data
      * @return the decoded data
@@ -2424,7 +2479,7 @@
                 if (s == null)
                     continue;
                 String ns = BaseFont.createSubsetPrefix() + s.substring(7);
-                PdfName newName = new PdfName(ns);
+                PdfName newName = getPdfName(ns);
                 dic.put(PdfName.BASEFONT, newName);
                 setXrefPartialObject(k, dic);
                 ++total;
@@ -2445,10 +2500,11 @@
                 if (sde == null)
                     continue;
                 String ns = BaseFont.createSubsetPrefix();
-                if (s != null)
-                    dic.put(PdfName.BASEFONT, new PdfName(ns + s.substring(7)));
+                if (s != null) {
+                    dic.put(PdfName.BASEFONT, getPdfName(ns + s.substring(7)));
+                }
                 setXrefPartialObject(k, dic);
-                PdfName newName = new PdfName(ns + sde.substring(7));
+                PdfName newName = getPdfName(ns + sde.substring(7));
                 desc.put(PdfName.BASEFONT, newName);
                 ++total;
                 PdfDictionary fd = desc.getAsDict(PdfName.FONTDESCRIPTOR);
@@ -2489,7 +2545,7 @@
                     && fd.get(PdfName.FONTFILE3) == null)
                     continue;
                 fd = dic.getAsDict(PdfName.FONTDESCRIPTOR);
-                PdfName newName = new PdfName(ns);
+                PdfName newName = getPdfName(ns);
                 dic.put(PdfName.BASEFONT, newName);
                 fd.put(PdfName.FONTNAME, newName);
                 setXrefPartialObject(k, dic);
@@ -3139,7 +3195,7 @@
             pageInh = new ArrayList();
             iteratePages((PRIndirectReference)reader.catalog.get(PdfName.PAGES));
             pageInh = null;
-            reader.rootPages.put(PdfName.COUNT, new PdfNumber(refsn.size()));
+            reader.rootPages.put(PdfName.COUNT, getPdfNumber(refsn.size()));
         }
 
         void reReadPages() throws IOException {
@@ -3404,7 +3460,7 @@
                     }
                 }
             }
-            topPages.put(PdfName.COUNT, new PdfNumber(finalPages.size()));
+            topPages.put(PdfName.COUNT, getPdfNumber(finalPages.size()));
             topPages.put(PdfName.KIDS, kids);
             refsp = null;
             refsn = newPageRefs;
@@ -3493,4 +3549,4 @@
     	if (!encrypted || !ownerPasswordUsed) return null;
     	return decrypt.computeUserPassword(password);
     }
-}
\ No newline at end of file
+}
--- src/core/com/lowagie/text/pdf/Type1Font.java	2010-09-27 23:48:35.000000000 -0700
+++ src/core/com/lowagie/text/pdf/Type1Font.java	2010-10-25 21:22:40.000000000 -0700
@@ -140,14 +140,18 @@
  *  Integer, Integer, String and int[]. This is the code, width, name and char bbox.
  *  The key is the name of the char and also an Integer with the char number.
  */
-    private HashMap CharMetrics = new HashMap();
+    // Initial capacity based on runtime data
+    private final HashMap CharMetrics = new HashMap(650);
+
 /** Represents the section KernPairs in the AFM file. The key is
  *  the name of the first character and the value is a <CODE>Object[]</CODE>
  *  with 2 elements for each kern pair. Position 0 is the name of
  *  the second character and position 1 is the kerning distance. This is
  *  repeated for all the pairs.
  */
-    private HashMap KernPairs = new HashMap();
+    // Initial capacity based on runtime data
+    private final HashMap KernPairs = new HashMap(200);
+
 /** The file in use.
  */
     private String fileName;
@@ -464,8 +468,9 @@
             String ident = tok.nextToken();
             if (ident.equals("KPX"))
             {
-                String first = tok.nextToken();
-                String second = tok.nextToken();
+                // intern these tokens to save memory
+                String first = tok.nextToken().intern();
+                String second = tok.nextToken().intern();
                 Integer width = new Integer((int)Float.parseFloat(tok.nextToken()));
                 Object relates[] = (Object[])KernPairs.get(first);
                 if (relates == null)
