diff --git a/project/SparkBuild.scala b/project/SparkBuild.scala
index 4bfa8cede7a8565a0f4086e561dbfd6b96dc5282..a93aa12ce1aac96299bf73e8dfda167a5c64dc9c 100644
--- a/project/SparkBuild.scala
+++ b/project/SparkBuild.scala
@@ -163,6 +163,9 @@ object SparkBuild extends PomBuild {
       x => enable(MimaBuild.mimaSettings(sparkHome, x))(x)
     }
 
+  /* Unsafe settings */
+  enable(Unsafe.settings)(unsafe)
+
   /* Enable Assembly for all assembly projects */
   assemblyProjects.foreach(enable(Assembly.settings))
 
@@ -216,6 +219,13 @@ object SparkBuild extends PomBuild {
 
 }
 
+object Unsafe {
+  lazy val settings = Seq(
+    // This option is needed to suppress warnings from sun.misc.Unsafe usage
+    javacOptions in Compile += "-XDignore.symbol.file"
+  )
+}
+
 object Flume {
   lazy val settings = sbtavro.SbtAvro.avroSettings
 }
@@ -424,6 +434,7 @@ object Unidoc {
       .map(_.filterNot(_.getCanonicalPath.contains("org/apache/spark/network")))
       .map(_.filterNot(_.getCanonicalPath.contains("org/apache/spark/shuffle")))
       .map(_.filterNot(_.getCanonicalPath.contains("org/apache/spark/executor")))
+      .map(_.filterNot(_.getCanonicalPath.contains("org/apache/spark/unsafe")))
       .map(_.filterNot(_.getCanonicalPath.contains("python")))
       .map(_.filterNot(_.getCanonicalPath.contains("org/apache/spark/util/collection")))
       .map(_.filterNot(_.getCanonicalPath.contains("org/apache/spark/sql/catalyst")))
diff --git a/unsafe/pom.xml b/unsafe/pom.xml
index 8901d77591932292a7db3c4ae349bad9bb9a04b8..5b0733206b2bc5de85b57cc45771cc55b8170cb3 100644
--- a/unsafe/pom.xml
+++ b/unsafe/pom.xml
@@ -65,5 +65,29 @@
   <build>
     <outputDirectory>target/scala-${scala.binary.version}/classes</outputDirectory>
     <testOutputDirectory>target/scala-${scala.binary.version}/test-classes</testOutputDirectory>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>net.alchim31.maven</groupId>
+          <artifactId>scala-maven-plugin</artifactId>
+          <configuration>
+            <javacArgs>
+              <!-- This option is needed to suppress warnings from sun.misc.Unsafe usage -->
+              <javacArg>-XDignore.symbol.file</javacArg>
+            </javacArgs>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <configuration>
+            <compilerArgs>
+              <!-- This option is needed to suppress warnings from sun.misc.Unsafe usage -->
+              <arg>-XDignore.symbol.file</arg>
+            </compilerArgs>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
   </build>
 </project>
diff --git a/unsafe/src/main/java/org/apache/spark/unsafe/PlatformDependent.java b/unsafe/src/main/java/org/apache/spark/unsafe/PlatformDependent.java
index 91b2f9aa439211b842410a26ff49fdd139a51e35..24b289209805942f824529257d523c216b68dc50 100644
--- a/unsafe/src/main/java/org/apache/spark/unsafe/PlatformDependent.java
+++ b/unsafe/src/main/java/org/apache/spark/unsafe/PlatformDependent.java
@@ -23,7 +23,82 @@ import sun.misc.Unsafe;
 
 public final class PlatformDependent {
 
-  public static final Unsafe UNSAFE;
+  /**
+   * Facade in front of {@link sun.misc.Unsafe}, used to avoid directly exposing Unsafe outside of
+   * this package. This also lets us aovid accidental use of deprecated methods or methods that
+   * aren't present in Java 6.
+   */
+  public static final class UNSAFE {
+
+    private UNSAFE() { }
+
+    public static int getInt(Object object, long offset) {
+      return _UNSAFE.getInt(object, offset);
+    }
+
+    public static void putInt(Object object, long offset, int value) {
+      _UNSAFE.putInt(object, offset, value);
+    }
+
+    public static boolean getBoolean(Object object, long offset) {
+      return _UNSAFE.getBoolean(object, offset);
+    }
+
+    public static void putBoolean(Object object, long offset, boolean value) {
+      _UNSAFE.putBoolean(object, offset, value);
+    }
+
+    public static byte getByte(Object object, long offset) {
+      return _UNSAFE.getByte(object, offset);
+    }
+
+    public static void putByte(Object object, long offset, byte value) {
+      _UNSAFE.putByte(object, offset, value);
+    }
+
+    public static short getShort(Object object, long offset) {
+      return _UNSAFE.getShort(object, offset);
+    }
+
+    public static void putShort(Object object, long offset, short value) {
+      _UNSAFE.putShort(object, offset, value);
+    }
+
+    public static long getLong(Object object, long offset) {
+      return _UNSAFE.getLong(object, offset);
+    }
+
+    public static void putLong(Object object, long offset, long value) {
+      _UNSAFE.putLong(object, offset, value);
+    }
+
+    public static float getFloat(Object object, long offset) {
+      return _UNSAFE.getFloat(object, offset);
+    }
+
+    public static void putFloat(Object object, long offset, float value) {
+      _UNSAFE.putFloat(object, offset, value);
+    }
+
+    public static double getDouble(Object object, long offset) {
+      return _UNSAFE.getDouble(object, offset);
+    }
+
+    public static void putDouble(Object object, long offset, double value) {
+      _UNSAFE.putDouble(object, offset, value);
+    }
+
+    public static long allocateMemory(long size) {
+      return _UNSAFE.allocateMemory(size);
+    }
+
+    public static void freeMemory(long address) {
+      _UNSAFE.freeMemory(address);
+    }
+
+  }
+
+  private static final Unsafe _UNSAFE;
 
   public static final int BYTE_ARRAY_OFFSET;
 
@@ -48,13 +123,13 @@ public final class PlatformDependent {
     } catch (Throwable cause) {
       unsafe = null;
     }
-    UNSAFE = unsafe;
+    _UNSAFE = unsafe;
 
-    if (UNSAFE != null) {
-      BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
-      INT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class);
-      LONG_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(long[].class);
-      DOUBLE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(double[].class);
+    if (_UNSAFE != null) {
+      BYTE_ARRAY_OFFSET = _UNSAFE.arrayBaseOffset(byte[].class);
+      INT_ARRAY_OFFSET = _UNSAFE.arrayBaseOffset(int[].class);
+      LONG_ARRAY_OFFSET = _UNSAFE.arrayBaseOffset(long[].class);
+      DOUBLE_ARRAY_OFFSET = _UNSAFE.arrayBaseOffset(double[].class);
     } else {
       BYTE_ARRAY_OFFSET = 0;
       INT_ARRAY_OFFSET = 0;
@@ -71,7 +146,7 @@ public final class PlatformDependent {
       long length) {
     while (length > 0) {
       long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
-      UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, size);
+      _UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, size);
       length -= size;
       srcOffset += size;
       dstOffset += size;
@@ -82,6 +157,6 @@ public final class PlatformDependent {
    * Raises an exception bypassing compiler checks for checked exceptions.
    */
   public static void throwException(Throwable t) {
-    UNSAFE.throwException(t);
+    _UNSAFE.throwException(t);
   }
 }
diff --git a/unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java b/unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java
index 85b64c083380380d1b2b999f5d199ddc49dfd86d..4e5ebc402be35849378a432f34aa59c9c0f0c4da 100644
--- a/unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java
+++ b/unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java
@@ -401,11 +401,11 @@ public final class BytesToBytesMap {
 
       // Copy the key
       PlatformDependent.UNSAFE.putLong(pageBaseObject, keySizeOffsetInPage, keyLengthBytes);
-      PlatformDependent.UNSAFE.copyMemory(
+      PlatformDependent.copyMemory(
         keyBaseObject, keyBaseOffset, pageBaseObject, keyDataOffsetInPage, keyLengthBytes);
       // Copy the value
       PlatformDependent.UNSAFE.putLong(pageBaseObject, valueSizeOffsetInPage, valueLengthBytes);
-      PlatformDependent.UNSAFE.copyMemory(
+      PlatformDependent.copyMemory(
         valueBaseObject, valueBaseOffset, pageBaseObject, valueDataOffsetInPage, valueLengthBytes);
 
       final long storedKeyAddress = memoryManager.encodePageNumberAndOffset(
@@ -429,7 +429,7 @@ public final class BytesToBytesMap {
   private void allocate(int capacity) {
     capacity = Math.max((int) Math.min(Integer.MAX_VALUE, nextPowerOf2(capacity)), 64);
     longArray = new LongArray(memoryManager.allocate(capacity * 8 * 2));
-    bitset = new BitSet(memoryManager.allocate(capacity / 8).zero());
+    bitset = new BitSet(MemoryBlock.fromLongArray(new long[capacity / 64]));
 
     this.growthThreshold = (int) (capacity * loadFactor);
     this.mask = capacity - 1;
@@ -447,7 +447,7 @@ public final class BytesToBytesMap {
       longArray = null;
     }
     if (bitset != null) {
-      memoryManager.free(bitset.memoryBlock());
+      // The bitset's heap memory isn't managed by a memory manager, so no need to free it here.
       bitset = null;
     }
     Iterator<MemoryBlock> dataPagesIterator = dataPages.iterator();
@@ -535,7 +535,6 @@ public final class BytesToBytesMap {
 
     // Deallocate the old data structures.
     memoryManager.free(oldLongArray.memoryBlock());
-    memoryManager.free(oldBitSet.memoryBlock());
     if (enablePerfMetrics) {
       timeSpentResizingNs += System.nanoTime() - resizeStartTime;
     }
diff --git a/unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java b/unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java
index 0beb743e5644eea312eedd235f2bde1a289ffd12..3dc82d8c2eb399ac86571126a29724c0d994c914 100644
--- a/unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java
+++ b/unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java
@@ -46,14 +46,6 @@ public class MemoryBlock extends MemoryLocation {
     return length;
   }
 
-  /**
-   * Clear the contents of this memory block.  Returns `this` to facilitate chaining.
-   */
-  public MemoryBlock zero() {
-    PlatformDependent.UNSAFE.setMemory(obj, offset, length, (byte) 0);
-    return this;
-  }
-
   /**
    * Creates a memory block pointing to the memory used by the long array.
    */
diff --git a/unsafe/src/test/java/org/apache/spark/unsafe/bitset/BitSetSuite.java b/unsafe/src/test/java/org/apache/spark/unsafe/bitset/BitSetSuite.java
index 4bf132fd4053e01320ecf006b6c4b86535de6fd9..e3a824e29b76869bee2bcec2b88e94e3d061fa5d 100644
--- a/unsafe/src/test/java/org/apache/spark/unsafe/bitset/BitSetSuite.java
+++ b/unsafe/src/test/java/org/apache/spark/unsafe/bitset/BitSetSuite.java
@@ -27,7 +27,7 @@ public class BitSetSuite {
 
   private static BitSet createBitSet(int capacity) {
     assert capacity % 64 == 0;
-    return new BitSet(MemoryBlock.fromLongArray(new long[capacity / 64]).zero());
+    return new BitSet(MemoryBlock.fromLongArray(new long[capacity / 64]));
   }
 
   @Test
diff --git a/unsafe/src/test/java/org/apache/spark/unsafe/map/AbstractBytesToBytesMapSuite.java b/unsafe/src/test/java/org/apache/spark/unsafe/map/AbstractBytesToBytesMapSuite.java
index 9038cf567f1e2d5e3b3f0c221acf6bcfdb9024d2..7a5c0622d1ffbabd08cd61722548d319e98d1ba7 100644
--- a/unsafe/src/test/java/org/apache/spark/unsafe/map/AbstractBytesToBytesMapSuite.java
+++ b/unsafe/src/test/java/org/apache/spark/unsafe/map/AbstractBytesToBytesMapSuite.java
@@ -57,7 +57,7 @@ public abstract class AbstractBytesToBytesMapSuite {
 
   private static byte[] getByteArray(MemoryLocation loc, int size) {
     final byte[] arr = new byte[size];
-    PlatformDependent.UNSAFE.copyMemory(
+    PlatformDependent.copyMemory(
       loc.getBaseObject(),
       loc.getBaseOffset(),
       arr,