Index: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 3128)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 3129)
@@ -55,4 +55,6 @@
     private static final int FLAG_TAGGED = 1 << 6;
     private static final int FLAG_DIRECTION_REVERSED = 1 << 7;
+    private static final int FLAG_HIGHLIGHTED = 1 << 8;
+    private static final int FLAG_INCOMPLETE = 1 << 9;
 
     /**
@@ -119,5 +121,5 @@
     /* mappaint data */
     public ElemStyle mappaintStyle = null;
-    public Integer mappaintDrawnCode = 0;
+    public int mappaintDrawnCode = 0;
 
     /* This should not be called from outside. Fixing the UI to add relevant
@@ -168,5 +170,5 @@
     }
 
-    private volatile byte flags = FLAG_VISIBLE;   // visible per default
+    private volatile short flags = FLAG_VISIBLE;   // visible per default
 
     /**
@@ -175,10 +177,4 @@
      */
     private User user = null;
-
-    /**
-     * If set to true, this object is incomplete, which means only the id
-     * and type is known (type is the objects instance class)
-     */
-    private boolean incomplete = false;
 
     /**
@@ -333,10 +329,9 @@
      */
     public boolean isUsable() {
-        return !isDeleted() && !isIncomplete() && !isDisabled();
-    }
-
-    public boolean isDrawable()
-    {
-        return !isDeleted() && !isIncomplete() && !isFiltered();
+        return (flags & (FLAG_DELETED + FLAG_INCOMPLETE + FLAG_DISABLED)) == 0;
+    }
+
+    public boolean isDrawable() {
+        return (flags & (FLAG_DELETED + FLAG_INCOMPLETE + FLAG_FILTERED)) == 0;
     }
 
@@ -470,10 +465,4 @@
         return timestamp == 0;
     }
-
-    /**
-     * If set to true, this object is highlighted. Currently this is only used to
-     * show which ways/nodes will connect
-     */
-    private volatile boolean highlighted = false;
 
     private int timestamp;
@@ -1270,6 +1259,10 @@
     }
 
+    /**
+     * If set to true, this object is incomplete, which means only the id
+     * and type is known (type is the objects instance class)
+     */
     private void setIncomplete(boolean incomplete) {
-        if (dataSet != null && incomplete != this.incomplete) {
+        if (dataSet != null && incomplete != this.isIncomplete()) {
             if (incomplete) {
                 dataSet.firePrimitivesRemoved(Collections.singletonList(this), true);
@@ -1278,9 +1271,13 @@
             }
         }
-        this.incomplete = incomplete;
+        if (incomplete) {
+            flags |= FLAG_INCOMPLETE;
+        } else {
+            flags &= ~FLAG_INCOMPLETE;
+        }
     }
 
     public boolean isIncomplete() {
-        return incomplete;
+        return (flags & FLAG_INCOMPLETE) != 0;
     }
 
@@ -1290,6 +1287,10 @@
 
     public void setHighlighted(boolean highlighted) {
-        if (this.highlighted != highlighted) {
-            this.highlighted = highlighted;
+        if (isHighlighted() != highlighted) {
+            if (highlighted) {
+                flags |= FLAG_HIGHLIGHTED;
+            } else {
+                flags &= ~FLAG_HIGHLIGHTED;
+            }
             if (dataSet != null) {
                 dataSet.fireHighlightingChanged(this);
@@ -1299,5 +1300,5 @@
 
     public boolean isHighlighted() {
-        return highlighted;
+        return (flags & FLAG_HIGHLIGHTED) != 0;
     }
 }
Index: trunk/src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 3128)
+++ trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 3129)
@@ -32,4 +32,5 @@
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
+import org.openstreetmap.josm.data.osm.Storage;
 import org.openstreetmap.josm.data.osm.User;
 import org.openstreetmap.josm.data.osm.Way;
@@ -119,6 +120,18 @@
         private long currentExternalId;
         private String generator;
+        private Storage<String> internedStrings = new Storage<String>();
+
+        // Memory optimization - see #2312
+        private String intern(String s) {
+            String result = internedStrings.get(s);
+            if (result == null) {
+                internedStrings.put(s);
+                return s;
+            } else
+                return result;
+        }
 
         @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
+
             if (qName.equals("osm")) {
                 if (atts == null) {
@@ -258,5 +271,6 @@
                 String key = atts.getValue("k");
                 String value = atts.getValue("v");
-                currentPrimitive.put(key, value);
+                currentPrimitive.put(intern(key), intern(value));
+
             } else {
                 System.out.println(tr("Undefined element ''{0}'' found in input stream. Skipping.", qName));
