Merge branch 'master' into fix_issue_178
diff --git a/.asf.yaml b/.asf.yaml
index 15e33a5..45d974b 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -1,2 +1,4 @@
 github:
-  homepage: https://datasketches.apache.org
\ No newline at end of file
+  homepage: https://datasketches.apache.org
+  ghp_branch: gh-pages
+  ghp_path: /docs
diff --git a/.github/workflows/.toolchains.xml b/.github/workflows/.toolchains.xml
index 70b6e51..5f40493 100644
--- a/.github/workflows/.toolchains.xml
+++ b/.github/workflows/.toolchains.xml
@@ -30,24 +30,4 @@
             <jdkHome>${env.JAVA11_HOME}</jdkHome>
         </configuration>
     </toolchain>
-    <toolchain>
-        <type>jdk</type>
-        <provides>
-            <version>12</version>
-            <vendor>openjdk</vendor>
-        </provides>
-        <configuration>
-            <jdkHome>${env.JAVA12_HOME}</jdkHome>
-        </configuration>
-    </toolchain>
-    <toolchain>
-        <type>jdk</type>
-        <provides>
-            <version>13</version>
-            <vendor>openjdk</vendor>
-        </provides>
-        <configuration>
-            <jdkHome>${env.JAVA13_HOME}</jdkHome>
-        </configuration>
-    </toolchain>
 </toolchains>
\ No newline at end of file
diff --git a/.github/workflows/auto-jdk-matrix.yml b/.github/workflows/auto-jdk-matrix.yml
new file mode 100644
index 0000000..c0ec959
--- /dev/null
+++ b/.github/workflows/auto-jdk-matrix.yml
@@ -0,0 +1,65 @@
+name: DataSketches-Memory Auto JDK Matrix Test & Install
+
+on:
+    pull_request:
+    push:
+        branches: [ master ]
+    workflow_dispatch:
+
+env:
+    MAVEN_OPTS: -Xmx4g -Xms1g
+
+jobs:
+    build:
+        name: Build, Test, Install
+        runs-on: macOS-latest
+
+        strategy:
+          fail-fast: false
+
+        steps:
+        - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
+          uses: actions/checkout@v3.3.0
+          with:
+              persist-credentials: false
+
+        - name: Cache local Maven repository
+          uses: actions/cache@v3.2.3
+          with:
+              path: ~/.m2/repository
+              key: build-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+              restore-keys: build-${{ runner.os }}-maven-
+
+        - name: Install Matrix JDK
+          uses: actions/setup-java@v3
+          with:
+              java-version: |
+                  8
+                  11
+              distribution: 'temurin'
+              java-package: jdk
+              architecture: x64 
+
+        - name: Echo Java Version
+          run: >
+              java -version
+
+        - name: Test
+          run: >
+              mvn clean test -B -X
+              -Dmaven.javadoc.skip=true
+              -Dgpg.skip=true
+
+        - name: Install
+          run: >
+              mvn clean install -B -X
+              -DskipTests=true
+              -Dgpg.skip=true
+
+# Architecture options: x86, x64, armv7, aarch64, ppc64le
+# setup-java@v3 has a "with cache" option
+# Lifecycle: validate, compile, test, package, verify, install, deploy
+# -B batch mode
+# -V show Version without stopping
+# -X debug mode
+# -q quiet, only show errors
diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml
new file mode 100644
index 0000000..aeff17b
--- /dev/null
+++ b/.github/workflows/javadoc.yml
@@ -0,0 +1,23 @@
+name: JavaDoc
+
+on:
+  push:
+    branches:
+      - master
+  workflow_dispatch:
+
+jobs:
+  javadoc:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Generate JavaDoc
+        run: mvn javadoc:javadoc
+      - name: Deploy JavaDoc
+        uses: JamesIves/github-pages-deploy-action@5dc1d5a192aeb5ab5b7d5a77b7d36aea4a7f5c92
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
+          folder: datasketches-memory-java8/target/site/apidocs
+          target-folder: docs/${{ github.ref_name }}
+          branch: gh-pages
diff --git a/.github/workflows/manual-coverage.yml b/.github/workflows/manual-coverage.yml
new file mode 100644
index 0000000..03320e5
--- /dev/null
+++ b/.github/workflows/manual-coverage.yml
@@ -0,0 +1,71 @@
+name: Datasketches-Memory Manual Coverage Report
+
+on:
+    workflow_dispatch:
+
+env:
+    MAVEN_OPTS: -Xmx4g -Xms1g
+
+jobs:
+    build:
+        name: Build, Test, Coverage
+        runs-on: ${{matrix.os}}
+        strategy:
+          fail-fast: false
+          matrix:
+            jdk: [ 8 ]
+            os: [ ubuntu-latest ]
+            include:
+#              - os: windows-latest
+#                skip_javadoc: "`-Dmaven`.javadoc`.skip=true"
+#                skip_gpg: "`-Dgpg`.skip=true"
+              - os: ubuntu-latest
+                skip_javadoc: -Dmaven.javadoc.skip=true
+                skip_gpg: -Dgpg.skip=true
+#              - os: macos-latest
+#                skip_javadoc: -Dmaven.javadoc.skip=true
+#                skip_gpg: -Dgpg.skip=true
+
+        env:
+          JDK_VERSION: ${{ matrix.jdk }}
+
+        steps:
+        - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
+          uses: actions/checkout@v3
+          with:
+              persist-credentials: false
+
+        - name: Cache local Maven repository
+          uses: actions/cache@v3
+          with:
+              path: ~/.m2/repository
+              key: build-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+              restore-keys: build-${{ runner.os }}-maven-
+
+        - name: Install Matrix JDK
+          uses: actions/setup-java@v3
+          with:
+              java-version: ${{ matrix.jdk }}
+              distribution: 'temurin'
+              java-package: jdk
+              architecture: x64 
+# Architecture options: x86, x64, armv7, aarch64, ppc64le
+# setup-java@v3 has a "with cache" option
+
+        - name: Echo Java Version
+          run: >
+              java -version
+
+        - name: Test, Package, Verify, Coverage Report
+          if: ${{ matrix.jdk == 8 && success() }}
+          run: 
+              mvn verify coveralls:report -B
+              -DrepoToken=${{secrets.coveralls_token}}
+              ${{matrix.os.skip_javadoc}}
+              ${{matrix.os.skip_gpg}}
+              
+# Lifecycle: validate, compile, test, package, verify, install, deploy
+# Coverage reports are available after the verify phase
+# -B batch mode
+# -V show Version without stopping
+# -q quiet, only show errors
diff --git a/.github/workflows/manual-os-matrix.yml b/.github/workflows/manual-os-matrix.yml
new file mode 100644
index 0000000..9e2d36f
--- /dev/null
+++ b/.github/workflows/manual-os-matrix.yml
@@ -0,0 +1,78 @@
+name: DataSketches-Memory Manual OS Matrix Test & Install
+
+on:
+    workflow_dispatch:
+
+env:
+    MAVEN_OPTS: -Xmx4g -Xms1g
+
+jobs:
+    build:
+        name: Build, Test, Install
+
+        strategy:
+          fail-fast: false
+
+          matrix:
+            jdk: [ 8, 11 ]
+            os: [ windows-latest, ubuntu-latest, macos-latest ]
+            include:
+              - os: windows-latest
+                skip_javadoc: "`-Dmaven`.javadoc`.skip=true"
+                skip_gpg: "`-Dgpg`.skip=true"
+              - os: ubuntu-latest
+                skip_javadoc: -Dmaven.javadoc.skip=true
+                skip_gpg: -Dgpg.skip=true
+              - os: macos-latest
+                skip_javadoc: -Dmaven.javadoc.skip=true
+                skip_gpg: -Dgpg.skip=true
+
+        runs-on: ${{matrix.os}}
+
+        env:
+          JDK_VERSION: ${{ matrix.jdk }}
+
+        steps:
+        - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
+          uses: actions/checkout@v3
+          with:
+              persist-credentials: false
+
+        - name: Cache local Maven repository
+          uses: actions/cache@v3
+          with:
+              path: ~/.m2/repository
+              key: build-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+              restore-keys: build-${{ runner.os }}-maven-
+
+        - name: Install Matrix JDK
+          uses: actions/setup-java@v3
+          with:
+              java-version: ${{ matrix.jdk }}
+              distribution: 'temurin'
+              java-package: jdk
+              architecture: x64 
+# Architecture options: x86, x64, armv7, aarch64, ppc64le
+# setup-java@v3 has a "with cache" option
+
+        - name: Echo Java Version
+          run: >
+              java -version
+
+        - name: Test
+          run: >
+              mvn clean test
+              ${{matrix.os.skip_javadoc}}
+              ${{matrix.os.skip_gpg}}
+
+        - name: Install
+          run: >
+              mvn clean install -B
+              ${{matrix.os.skip_javadoc}}
+              -D skipTests=true
+              ${{matrix.os.skip_gpg}}
+
+# Lifecycle: validate, compile, test, package, verify, install, deploy
+# -B batch mode
+# -V show Version without stopping
+# -q quiet, only show errors
diff --git a/.github/workflows/manual-share-data.yml b/.github/workflows/manual-share-data.yml
new file mode 100644
index 0000000..c1db1e6
--- /dev/null
+++ b/.github/workflows/manual-share-data.yml
@@ -0,0 +1,86 @@
+name: Manual share data
+
+on:
+    workflow_dispatch:
+
+jobs:
+  job_1:
+    name: Add 3 and 7
+    runs-on: macOS-latest
+
+    steps:
+      - shell: bash
+        run: |
+          expr 3 + 7 > math-homework.txt
+
+      - name: Upload math result for job_2
+        uses: actions/upload-artifact@v3
+        with:
+          name: homework
+          path: math-homework.txt
+
+  job_2:
+    name: Multiply by 9
+    needs: job_1
+    runs-on: macOS-latest
+
+    steps:
+      - name: Download math result from job_1
+        uses: actions/download-artifact@v3
+        with:
+          name: homework
+
+      - shell: bash
+        run: |
+          value=`cat math-homework.txt`
+          expr $value \* 9 > math-homework.txt
+
+      - name: Upload math result from job_2 to job_3
+        uses: actions/upload-artifact@v3
+        with:
+          name: homework
+          path: math-homework.txt
+
+  job_3:
+    name: Display results
+    needs: job_2
+    runs-on: macOS-latest
+
+    steps:
+      - name: Download math result from job_2
+        uses: actions/download-artifact@v3
+        with:
+          name: homework
+
+      - name: Print the final result
+        shell: bash
+        run: |
+          value=`cat math-homework.txt`
+          echo The result is $value
+
+      - name: Upload result from job_3 to job_4
+        uses: actions/upload-artifact@v3
+        with:
+          name: homework
+          path: math-homework.txt
+
+  job_4:
+    name: Install tree and output
+    needs: job_3
+    runs-on: macOS-latest
+
+    steps:
+      - name: Download math result from job-3
+        uses: actions/download-artifact@v3
+        with:
+          name: homework
+
+      - name: Check out repository code
+        uses: actions/checkout@v3
+
+      - name: update brew, install tree, output
+        run: |
+          brew update
+          brew install tree
+          tree /Users/runner/work
+          
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
deleted file mode 100644
index 22fc03f..0000000
--- a/.github/workflows/maven.yml
+++ /dev/null
@@ -1,119 +0,0 @@
-name: Java Test Coverage with Maven, Coveralls
-
-on:
-  pull_request:
-  push:
-    branches: [ master ]
-  workflow_dispatch:
-
-env:
-  MAVEN_OPTS: -Xmx4g -Xms1g
-  repo_token: ${{secrets.coveralls_token}}
-  RUNNER_TEMP: /tmp
-
-jobs:
-  build:
-    name: Build, Test, Coverage
-    runs-on: ubuntu-latest
-    strategy:
-      fail-fast: false
-      matrix:
-        jdk: [8,11,12,13]
-
-    # All JDKs are installed per build machine which is inefficient
-
-    env:
-      JDK_VERSION: ${{ matrix.jdk }}
-
-    steps:
-      - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
-        uses: actions/checkout@v2
-        with:
-          persist-credentials: false
-
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: build-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
-          restore-keys: build-${{ runner.os }}-maven-
-
-      - name: Install JDK 8
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: '8'
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA8_HOME'
-
-      - name: Install JDK 11
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: '11'
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA11_HOME'
-
-      - name: Install JDK 12
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: '12'
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA12_HOME'
-
-      - name: Install JDK 13
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: '13'
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA13_HOME'
-
-      - name: Install Matrix JDK
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: ${{ matrix.jdk }}
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA_HOME'
-
-      - name: Echo Java Version
-        run: >
-          java -version
-
-      - name: Compile
-        run: >
-          mvn clean compile
-          -Dmaven.javadoc.skip=true
-          -Dgpg.skip=true
-          --toolchains .github/workflows/.toolchains.xml
-
-      - name: Install Dependencies
-        run: >
-          mvn clean install
-          -DskipTests=true
-          -Dgpg.skip=true
-          --toolchains .github/workflows/.toolchains.xml
-
-      - name: Package
-        run: >
-          mvn package
-          -Dmaven.javadoc.skip=false
-          -Dgpg.skip=true
-          --toolchains .github/workflows/.toolchains.xml
-
-      # The GitTag for CI purposes is irrelevant
-      - name: Custom build script
-        run: |
-          ./tools/scripts/package-single-release-jar.sh $JAVA_HOME x.y.z .
-        shell: bash
-
-      - name: Test & Report
-        if: ${{ matrix.jdk == 8 && success() }}
-        run: >
-          mvn verify coveralls:report -B -V
-          -Dcoveralls-repo-token=${repo_token}
-          -Dmaven.javadoc.skip=true
-          -Dgpg.skip=true
-          --toolchains .github/workflows/.toolchains.xml
diff --git a/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/Map.java b/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/MemoryException.java
similarity index 60%
rename from datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/Map.java
rename to datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/MemoryException.java
index 6b99059..6b3663c 100644
--- a/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/Map.java
+++ b/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/MemoryException.java
@@ -20,27 +20,23 @@
 package org.apache.datasketches.memory;
 
 /**
- * Read only interface for a memory mapped file
+ * Specific RuntimeExceptions for the datasketches-memory component.
  *
- * @author Roman Leventov
  * @author Lee Rhodes
- * @author Praveenkumar Venkatesan
+ *
  */
-public interface Map extends AutoCloseable {
+public class MemoryException extends RuntimeException {
+  private static final long serialVersionUID = 1L;
 
   /**
-   * @see <a href="https://docs.oracle.com/javase/8/docs/api/java/nio/MappedByteBuffer.html#load--">
-   * java/nio/MappedByteBuffer.load</a>
-   */
-  void load();
-
-  /**
-   * @return true if loaded
+   * Constructs a new runtime exception with the specified detail message. The cause is not
+   * initialized, and may subsequently be initialized by a call to
+   * Throwable.initCause(java.lang.Throwable).
    *
-   * @see <a href=
-   * "https://docs.oracle.com/javase/8/docs/api/java/nio/MappedByteBuffer.html#isLoaded--"> java
-   * /nio/MappedByteBuffer.isLoaded</a>
+   * @param message the detail message. The detail message is saved for later retrieval by the
+   * Throwable.getMessage() method.
    */
-  boolean isLoaded();
-
+  public MemoryException(final String message) {
+    super(message);
+  }
 }
diff --git a/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/MemoryCleaner.java b/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/MemoryCleaner.java
index f78801f..fd21f11 100644
--- a/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/MemoryCleaner.java
+++ b/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/MemoryCleaner.java
@@ -28,6 +28,7 @@
  * depending on the Java version that is used.
  * For more information, see: https://openjdk.java.net/jeps/238
  */
+//@SuppressWarnings("restriction")
 public class MemoryCleaner {
   private final Cleaner cleaner;
 
diff --git a/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/NioBitsFields.java b/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/NioBitsFields.java
deleted file mode 100644
index 633c685..0000000
--- a/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/NioBitsFields.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-/**
- * Extracts version-dependent field names into standalone class.
- * Some field names in the VM internal class have changed in
- * later versions. The appropriate class will be loaded by the class loader
- * depending on the Java version that is used.
- * For more information, see: https://openjdk.java.net/jeps/238
- */
-class NioBitsFields {
-    static String COUNT_FIELD_NAME = "COUNT";
-    static String RESERVED_MEMORY_FIELD_NAME = "RESERVED_MEMORY";
-    static String TOTAL_CAPACITY_FIELD_NAME = "TOTAL_CAPACITY";
-}
diff --git a/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/VirtualMachineMemory.java b/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/VirtualMachineMemory.java
index be91fad..6056fd9 100644
--- a/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/VirtualMachineMemory.java
+++ b/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/internal/VirtualMachineMemory.java
@@ -23,32 +23,23 @@
 import java.lang.reflect.Method;
 
 /**
- * Extracts a version-dependent reference to the `jdk.internal.misc.VM` into
- * a standalone class. The package name for VM has changed in
- * later versions. The appropriate class will be loaded by the class loader
- * depending on the Java version that is used.
+ * Extracts a version-dependent reference to the `jdk.internal.misc.VM` into a standalone
+ * class. The package name for VM has changed in later versions. The appropriate
+ * class will be loaded by the class loader depending on the Java version that is used.
  * For more information, see: https://openjdk.java.net/jeps/238
  */
 public final class VirtualMachineMemory {
 
   private static final Class<?> VM_CLASS;
-  private static final Method VM_MAX_DIRECT_MEMORY_METHOD;
   private static final Method VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD;
-  private static final long maxDBBMemory;
   private static final boolean isPageAligned;
 
   static {
     try {
       VM_CLASS = Class.forName("jdk.internal.misc.VM");
-      VM_MAX_DIRECT_MEMORY_METHOD = VM_CLASS.getDeclaredMethod("maxDirectMemory");
-      VM_MAX_DIRECT_MEMORY_METHOD.setAccessible(true);
-      maxDBBMemory = (long) VM_MAX_DIRECT_MEMORY_METHOD.invoke(null); //static method
-
-      VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD =
-          VM_CLASS.getDeclaredMethod("isDirectMemoryPageAligned");
+      VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD = VM_CLASS.getDeclaredMethod("isDirectMemoryPageAligned");
       VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD.setAccessible(true);
-      isPageAligned = (boolean) VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD
-          .invoke(null); //static method
+      isPageAligned = (boolean) VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD.invoke(null); //static method
     } catch (final ClassNotFoundException | NoSuchMethodException |  IllegalAccessException
         | IllegalArgumentException | InvocationTargetException | SecurityException e) {
       throw new RuntimeException("Could not acquire jdk.internal.misc.VM: " + e.getClass());
@@ -56,15 +47,6 @@
   }
 
   /**
-   * Returns the maximum amount of allocatable direct buffer memory.
-   * The directMemory variable is initialized during system initialization.
-   * @return the maximum amount of allocatable direct buffer memory.
-   */
-  public static long getMaxDBBMemory() {
-    return maxDBBMemory;
-  }
-
-  /**
    * Returns true if the direct buffers should be page aligned.
    * @return flag that determines whether direct buffers should be page aligned.
    */
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MapHandle.java b/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/package-info.java
similarity index 74%
rename from datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MapHandle.java
rename to datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/package-info.java
index d0c498e..769cee0 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MapHandle.java
+++ b/datasketches-memory-java11/src/main/java/org/apache/datasketches/memory/package-info.java
@@ -18,13 +18,3 @@
  */
 
 package org.apache.datasketches.memory;
-
-/**
- * A Handle for a memory-mapped, read-only file resource. This
- * joins a Read-only Handle with an AutoCloseable Map resource.
- * Please read Javadocs for {@link Handle}.
- *
- * @author Lee Rhodes
- * @author Roman Leventov
- */
-public interface MapHandle extends Map, Handle { }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BaseBuffer.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BaseBuffer.java
index 3e1869e..4ba4ce0 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BaseBuffer.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BaseBuffer.java
@@ -22,9 +22,11 @@
 /**
  * Defines the relative positional API.
  *
+ * <p>The classes in this package are not thread-safe.</p>
+ *
  * @author Lee Rhodes
  */
-public interface BaseBuffer extends BaseState {
+public interface BaseBuffer extends Resource {
 
   /**
    * Increments the current position by the given increment.
@@ -83,42 +85,20 @@
 
   /**
    * Sets the current position.
-   * Asserts that the positional invariants are not violated,
-   * otherwise, if asserts are enabled throws an {@link AssertionError}.
    * @param position the given current position.
    * @return BaseBuffer
+   * @throws BufferPositionInvariantsException if positional invariants have been violated.
    */
   BaseBuffer setPosition(long position);
 
   /**
-   * Sets the current position.
-   * Checks that the positional invariants are not violated,
-   * otherwise, throws an {@link IllegalArgumentException}.
-   * @param position the given current position.
-   * @return BaseBuffer
-   */
-  BaseBuffer setAndCheckPosition(long position);
-
-  /**
    * Sets start position, current position, and end position.
-   * Asserts that the positional invariants are not violated,
-   * otherwise, if asserts are enabled throws an {@link AssertionError}.
    * @param start the start position in the buffer
    * @param position the current position between the start and end
    * @param end the end position in the buffer
    * @return BaseBuffer
+   * @throws BufferPositionInvariantsException if positional invariants have been violated.
    */
   BaseBuffer setStartPositionEnd(long start, long position, long end);
 
-  /**
-   * Sets start position, current position, and end position.
-   * Checks that the positional invariants are not violated,
-   * otherwise, throws an {@link IllegalArgumentException}.
-   * @param start the start position in the buffer
-   * @param position the current position between the start and end
-   * @param end the end position in the buffer
-   * @return BaseBuffer
-   */
-  BaseBuffer setAndCheckStartPositionEnd(long start, long position, long end);
-
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BaseState.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BaseState.java
deleted file mode 100644
index 2ec75cb..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BaseState.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import org.apache.datasketches.memory.internal.BaseStateImpl;
-
-/**
- * Keeps key configuration state for Memory and Buffer plus some common static variables
- * and check methods.
- *
- * @author Lee Rhodes
- */
-public interface BaseState {
-  /**
-   * The placeholder for the default MemoryRequestServer, if set at all.
-   */
-  static final MemoryRequestServer defaultMemReqSvr = null; //new DefaultMemoryRequestServer();
-
-  //Byte Order Related
-
-  /**
-   * Gets the current Type ByteOrder.
-   * This may be different from the ByteOrder of the backing resource and of the Native Byte Order.
-   * @return the current Type ByteOrder.
-   */
-  ByteOrder getTypeByteOrder();
-
-  /**
-   * Returns true if the Native ByteOrder is the same as the ByteOrder of the
-   * current Buffer or Memory and the same ByteOrder as the given byteOrder.
-   * @param byteOrder the given ByteOrder
-   * @return true if the Native ByteOrder is the same as the ByteOrder of the
-   * current Buffer or Memory and the same ByteOrder as the given byteOrder.
-   */
-  boolean isByteOrderCompatible(ByteOrder byteOrder);
-
-  /**
-   * Returns true if the given object is an instance of this class and has equal data contents.
-   * @param that the given object
-   * @return true if the given Object is an instance of this class and has equal data contents.
-   */
-  @Override
-  boolean equals(Object that);
-
-  /**
-   * Returns true if the given object is an instance of this class and has equal contents to
-   * this object in the given range of bytes. This will also check two distinct ranges within the
-   * same object for equals.
-   * @param thisOffsetBytes the starting offset in bytes for this object.
-   * @param that the given object
-   * @param thatOffsetBytes the starting offset in bytes for the given object
-   * @param lengthBytes the size of the range in bytes
-   * @return true if the given object has equal contents to this object in the given range of
-   * bytes.
-   */
-  boolean equalTo(long thisOffsetBytes, Object that,
-      long thatOffsetBytes, long lengthBytes);
-
-  /**
-   * Gets the backing ByteBuffer if it exists, otherwise returns null.
-   * @return the backing ByteBuffer if it exists, otherwise returns null.
-   */
-  ByteBuffer getByteBuffer();
-
-  /**
-   * Gets the capacity of this object in bytes
-   * @return the capacity of this object in bytes
-   */
-  long getCapacity();
-
-  /**
-   * Gets the cumulative offset in bytes of this object from the backing resource.
-   * This offset may also include other offset components such as the native off-heap
-   * memory address, DirectByteBuffer split offsets, region offsets, and unsafe arrayBaseOffsets.
-   *
-   * @return the cumulative offset in bytes of this object from the backing resource.
-   */
-  long getCumulativeOffset();
-
-  /**
-   * Gets the cumulative offset in bytes of this object from the backing resource including the given
-   * offsetBytes. This offset may also include other offset components such as the native off-heap
-   * memory address, DirectByteBuffer split offsets, region offsets, and unsafe arrayBaseOffsets.
-   *
-   * @param offsetBytes offset to be added to the cumulative offset.
-   * @return the cumulative offset in bytes of this object from the backing resource including the
-   * given offsetBytes.
-   */
-  long getCumulativeOffset(long offsetBytes);
-
-  /**
-   * Returns the offset of address zero of this object relative to the address zero of the
-   * backing resource but not including the size of any Java object header.
-   * @return the offset of address zero of this object relative to the address zero of the
-   * backing resource but not including the size of any Java object header.
-   */
-  long getRegionOffset();
-
-  /**
-   * Returns the offset of address zero of this object relative to the address zero of the
-   * backing resource plus the given offsetBytes but not including the size of any Java object
-   * header.
-   * @param offsetBytes the given offsetBytes
-   * @return the offset of address zero of this object relative to the address zero of the
-   * backing resource plus the given offsetBytes but not including the size of any Java object
-   * header.
-   */
-  long getRegionOffset(long offsetBytes);
-
-  /**
-   * Returns true if this object is backed by an on-heap primitive array
-   * @return true if this object is backed by an on-heap primitive array
-   */
-  boolean hasArray();
-
-  /**
-   * Returns the hashCode of this object.
-   *
-   * <p>The hash code of this object depends upon all of its contents.
-   * Because of this, it is inadvisable to use these objects as keys in hash maps
-   * or similar data structures unless it is known that their contents will not change.</p>
-   *
-   * <p>If it is desirable to use these objects in a hash map depending only on object identity,
-   * than the {@link java.util.IdentityHashMap} can be used.</p>
-   *
-   * @return the hashCode of this object.
-   */
-  @Override
-  int hashCode();
-
-  /**
-   * Returns the 64-bit hash of the sequence of bytes in this object specified by
-   * <i>offsetBytes</i>, <i>lengthBytes</i> and a <i>seed</i>.  Note that the sequence of bytes is
-   * always processed in the same order independent of endianness.
-   *
-   * @param offsetBytes the given offset in bytes to the first byte of the byte sequence.
-   * @param lengthBytes the given length in bytes of the byte sequence.
-   * @param seed the given long seed.
-   * @return the 64-bit hash of the sequence of bytes in this object specified by
-   * <i>offsetBytes</i> and <i>lengthBytes</i>.
-   */
-  long xxHash64(long offsetBytes, long lengthBytes, long seed);
-
-  /**
-   * Returns a 64-bit hash from a single long. This method has been optimized for speed when only
-   * a single hash of a long is required.
-   * @param in A long.
-   * @param seed A long valued seed.
-   * @return the hash.
-   */
-  long xxHash64(long in, long seed);
-
-  /**
-   * Returns true if this Memory is backed by a ByteBuffer.
-   * @return true if this Memory is backed by a ByteBuffer.
-   */
-  boolean hasByteBuffer();
-
-  /**
-   * Returns true if the backing resource is direct (off-heap) memory.
-   * This is the case for allocated direct memory, memory mapped files,
-   * @return true if the backing resource is direct (off-heap) memory.
-   */
-  boolean isDirect();
-
-  /**
-   * Returns true if this object or the backing resource is read-only.
-   * @return true if this object or the backing resource is read-only.
-   */
-  boolean isReadOnly();
-
-  /**
-   * Returns true if the backing resource of <i>this</i> is identical with the backing resource
-   * of <i>that</i>. The capacities must be the same.  If <i>this</i> is a region,
-   * the region offset must also be the same.
-   * @param that A different non-null object
-   * @return true if the backing resource of <i>this</i> is the same as the backing resource
-   * of <i>that</i>.
-   */
-  boolean isSameResource(Object that);
-
-  /**
-   * Returns true if this object is valid and has not been closed.
-   * This is relevant only for direct (off-heap) memory and Mapped Files.
-   * @return true if this object is valid and has not been closed.
-   */
-  boolean isValid();
-
-  /**
-   * Checks that the specified range of bytes is within bounds of this object, throws
-   * {@link IllegalArgumentException} if it's not: i. e. if offsetBytes &lt; 0, or length &lt; 0,
-   * or offsetBytes + length &gt; {@link #getCapacity()}.
-   * @param offsetBytes the given offset in bytes of this object
-   * @param lengthBytes the given length in bytes of this object
-   */
-  void checkValidAndBounds(long offsetBytes, long lengthBytes);
-
-  //Monitoring
-
-  /**
-   * Gets the current number of active direct memory allocations.
-   * @return the current number of active direct memory allocations.
-   */
-  static long getCurrentDirectMemoryAllocations() {
-    return BaseStateImpl.getCurrentDirectMemoryAllocations();
-  }
-
-  /**
-   * Gets the current size of active direct memory allocated.
-   * @return the current size of active direct memory allocated.
-   */
-  static long getCurrentDirectMemoryAllocated() {
-    return BaseStateImpl.getCurrentDirectMemoryAllocated();
-  }
-
-  /**
-   * Gets the current number of active direct memory map allocations.
-   * @return the current number of active direct memory map allocations.
-   */
-  static long getCurrentDirectMemoryMapAllocations() {
-    return BaseStateImpl.getCurrentDirectMemoryMapAllocations();
-  }
-
-  /**
-   * Gets the current size of active direct memory map allocated.
-   * @return the current size of active direct memory map allocated.
-   */
-  static long getCurrentDirectMemoryMapAllocated() {
-    return BaseStateImpl.getCurrentDirectMemoryMapAllocated();
-  }
-
-  //TO STRING
-
-  /**
-   * Returns a formatted hex string of a range of this object.
-   * Used primarily for testing.
-   * @param header a descriptive header
-   * @param offsetBytes offset bytes relative to this object start
-   * @param lengthBytes number of bytes to convert to a hex string
-   * @return a formatted hex string in a human readable array
-   */
-  String toHexString(String header, long offsetBytes, int lengthBytes);
-
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Buffer.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Buffer.java
index fe4a9c8..c6d4156 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Buffer.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Buffer.java
@@ -30,6 +30,8 @@
 /**
  * Defines the read-only API for relative positional access to a resource.
  *
+ * <p>The classes in this package are not thread-safe.</p>
+ *
  * @author Lee Rhodes
  */
 public interface Buffer extends BaseBuffer {
@@ -143,7 +145,7 @@
    * @return Memory
    */
   default Memory asMemory() {
-    return asMemory(getTypeByteOrder());
+    return asMemory(getByteOrder());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMap.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BufferPositionInvariantsException.java
similarity index 70%
rename from datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMap.java
rename to datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BufferPositionInvariantsException.java
index 21502a7..c759645 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMap.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/BufferPositionInvariantsException.java
@@ -19,19 +19,16 @@
 
 package org.apache.datasketches.memory;
 
-/**
- * Writable interface for a memory mapped file
- *
- * @author Roman Leventov
- * @author Lee Rhodes
- * @author Praveenkumar Venkatesan
- */
-public interface WritableMap extends Map {
+public class BufferPositionInvariantsException extends MemoryException {
+  private static final long serialVersionUID = 1L;
 
   /**
-   * @see <a href="https://docs.oracle.com/javase/8/docs/api/java/nio/MappedByteBuffer.html#force--">
-   * java/nio/MappedByteBuffer.force</a>
+   * The associated position operation used violated the positional invariants equation with required details
+   *
+   * @param details of the violation.
    */
-  void force();
-
+  public BufferPositionInvariantsException(final String details) {
+    super(details);
+  }
 }
+
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java
index 51c2d2b..f8f828c 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java
@@ -73,7 +73,7 @@
    */
   @Override
   public WritableMemory request(final WritableMemory currentWritableMemory, final long capacityBytes) {
-    final WritableMemory wmem = WritableMemory.allocate((int)capacityBytes, currentWritableMemory.getTypeByteOrder());
+    final WritableMemory wmem = WritableMemory.allocate((int)capacityBytes, currentWritableMemory.getByteOrder());
     return wmem;
   }
 
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Handle.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Handle.java
deleted file mode 100644
index 92f0ca5..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Handle.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory;
-
-/**
- * A handle for read-only Memory resource.
- *
- * <p>The purpose of a Handle is to
- * <ul><li>Provide a <i>strong reference</i> to an external <i>resource</i>.</li>
- * <li>Extend <i>AutoCloseable</i>, which provides a means to close the resource.</li>
- * <li>Provide other capabilites unique to a particular resource.</li>
- * </ul>
- *
- * <p>Maintaining strong references to external resources is critical to avoid accidental
- * <i>use-after-free</i> scenarios, where the Garbage Collector will automatically close an external
- * resource if there are no remaining strong references to it. One very common mistake, is to allow
- * a newly created Handle to fall out-of-scope from the block where it was created, such as from a
- * try-with-resources statement. The Garbage Collector will eventually close the Handle referent
- * resource.</p>
- *
- * <p>Another <i>use-after-free</i> scenario is where a thread or agent, with access to the
- * Handle, prematurely closes a resource, when another part of the program is still using that
- * same resource. Avoiding this scenario requires careful planning and design.</p>
- *
- * <p>The design philosophy here is that whatever process created the external resource has the
- * responsibility to <i>close()</i> that resource when it is no longer needed.  This responsibility
- * can be delegated, by passing the appropriate Handle to the delegatee. In principle, however, at
- * any one time there should be only one agent holding the Handle and responsible for closing the
- * resource.</p>
- *
- * @author Lee Rhodes
- * @author Roman Leventov
- */
-public interface Handle extends AutoCloseable {
-
-  /**
-   * Gets a Memory
-   * @return a Memory
-   */
-  Memory get();
-
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Map.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Map.java
deleted file mode 100644
index 6b99059..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Map.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory;
-
-/**
- * Read only interface for a memory mapped file
- *
- * @author Roman Leventov
- * @author Lee Rhodes
- * @author Praveenkumar Venkatesan
- */
-public interface Map extends AutoCloseable {
-
-  /**
-   * @see <a href="https://docs.oracle.com/javase/8/docs/api/java/nio/MappedByteBuffer.html#load--">
-   * java/nio/MappedByteBuffer.load</a>
-   */
-  void load();
-
-  /**
-   * @return true if loaded
-   *
-   * @see <a href=
-   * "https://docs.oracle.com/javase/8/docs/api/java/nio/MappedByteBuffer.html#isLoaded--"> java
-   * /nio/MappedByteBuffer.isLoaded</a>
-   */
-  boolean isLoaded();
-
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Memory.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Memory.java
index 7c82882..eed7a4e 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Memory.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Memory.java
@@ -30,14 +30,16 @@
 
 import org.apache.datasketches.memory.internal.BaseWritableMemoryImpl;
 import org.apache.datasketches.memory.internal.Prim;
-import org.apache.datasketches.memory.internal.UnsafeUtil;
+import org.apache.datasketches.memory.internal.ResourceImpl;
 
 /**
  * Defines the read-only API for offset access to a resource.
  *
+ * <p>The classes in this package are not thread-safe.</p>
+ *
  * @author Lee Rhodes
  */
-public interface Memory extends BaseState {
+public interface Memory extends Resource {
 
   //BYTE BUFFER
 
@@ -71,10 +73,9 @@
    * Calling this method is equivalent to calling
    * {@link #map(File, long, long, ByteOrder) map(file, 0, file.length(), ByteOrder.nativeOrder())}.
    * @param file the given file to map. It must be non-null, length &ge; 0, and readable.
-   * @return <i>MapHandle</i> for managing the mapped memory.
-   * Please read Javadocs for {@link Handle}.
+   * @return <i>Memory</i> for managing the mapped memory.
    */
-  static MapHandle map(File file) {
+  static Memory map(File file) {
     return map(file, 0, file.length(), ByteOrder.nativeOrder());
   }
 
@@ -84,16 +85,15 @@
    * @param fileOffsetBytes the position in the given file in bytes. It must not be negative.
    * @param capacityBytes the size of the mapped memory. It must not be negative.
    * @param byteOrder the byte order to be used for the mapped memory. It must be non-null.
-   * @return <i>MapHandle</i> for managing the mapped memory.
-   * Please read Javadocs for {@link Handle}.
+   * @return <i>Memory</i> for managing the mapped memory.
    */
-  static MapHandle map(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) {
+  static Memory map(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) {
     Objects.requireNonNull(file, "file must be non-null.");
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
-    if (!file.canRead()) { throw new IllegalArgumentException("file must be readable."); }
+    if (!file.canRead()) { throw new ReadOnlyException("file must be readable."); }
     negativeCheck(fileOffsetBytes, "fileOffsetBytes");
     negativeCheck(capacityBytes, "capacityBytes");
-    return (MapHandle) BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, true, byteOrder);
+    return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, true, byteOrder);
   }
 
   //REGIONS
@@ -194,7 +194,7 @@
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
     negativeCheck(offsetBytes, "offsetBytes");
     negativeCheck(lengthBytes, "lengthBytes");
-    UnsafeUtil.checkBounds(offsetBytes, lengthBytes, array.length);
+    ResourceImpl.checkBounds(offsetBytes, lengthBytes, array.length);
     return BaseWritableMemoryImpl.wrapHeapArray(array, offsetBytes, lengthBytes, true, ByteOrder.nativeOrder(), null);
   }
 
@@ -484,5 +484,3 @@
       throws IOException;
 
 }
-
-
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableHandle.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MemoryBoundsException.java
similarity index 71%
rename from datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableHandle.java
rename to datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MemoryBoundsException.java
index 5546d5e..501012d 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableHandle.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MemoryBoundsException.java
@@ -20,17 +20,21 @@
 package org.apache.datasketches.memory;
 
 /**
- * A Handle for writable direct memory or a memory-mapped, writable file resource.
- * Please read Javadocs for {@link Handle}.
+ * Specific RuntimeException for bounds violations.
  *
  * @author Lee Rhodes
- * @author Roman Leventov
  */
-public interface WritableHandle extends Handle {
+public class MemoryBoundsException extends MemoryException {
+  private static final long serialVersionUID = 1L;
 
   /**
-   * Gets a WritableMemory
-   * @return a WritableMemory
+   * The associated operation violated access bounds with required details.
+   *
+   * @param details of the violation.
    */
-  WritableMemory getWritable();
+  public MemoryBoundsException(final String details) {
+    super(details);
+  }
+
 }
+
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MemoryCloseException.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MemoryCloseException.java
deleted file mode 100644
index 782c6cd..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MemoryCloseException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory;
-
-/**
- * Specific RuntimeException for the AutoCloseable.close() method.
- *
- * @author Lee Rhodes
- *
- */
-public class MemoryCloseException extends MemoryException {
-  private static final long serialVersionUID = 2L;
-
-  /**
-   * The associated resource failed to close.
-   */
-  public MemoryCloseException() {
-    super("The associated resource failed to close.");
-  }
-
-  /**
-   * The associated resource failed to close, with comment
-   *
-   * @param resource the named resource that failed to close, plus other comments.
-   */
-  public MemoryCloseException(final String resource) {
-    super("The associated resource, " + resource + ", failed to close");
-  }
-
-}
-
-
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MurmurHash3v2.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MurmurHash3v2.java
deleted file mode 100644
index 9c5a35b..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/MurmurHash3v2.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
-
-/**
- * <p>The MurmurHash3 is a fast, non-cryptographic, 128-bit hash function that has
- * excellent avalanche and 2-way bit independence properties.</p>
- *
- * <p>Austin Appleby's C++
- * <a href="https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp">
- * MurmurHash3_x64_128(...), final revision 150</a>,
- * which is in the Public Domain, was the inspiration for this implementation in Java.</p>
- *
- * <p>This implementation of the MurmurHash3 allows hashing of a block of on-heap Memory defined by an offset
- * and length. The calling API also allows the user to supply the small output array of two longs,
- * so that the entire hash function is static and free of object allocations.</p>
- *
- * <p>This implementation produces exactly the same hash result as the
- * MurmurHash3 function in datasketches-java given compatible inputs.</p>
- *
- * @author Lee Rhodes
- */
-public final class MurmurHash3v2 {
-  private static final long C1 = 0x87c37b91114253d5L;
-  private static final long C2 = 0x4cf5ad432745937fL;
-
-  //Provided for backward compatibility
-
-  /**
-   * Returns a 128-bit hash of the input.
-   * Provided for compatibility with older version of MurmurHash3,
-   * but empty or null input now throws IllegalArgumentException.
-   * @param in long array
-   * @param seed A long valued seed.
-   * @return the hash
-   */
-  public static long[] hash(final long[] in, final long seed) {
-    if ((in == null) || (in.length == 0)) {
-      throw new IllegalArgumentException("Input in is empty or null.");
-    }
-    return hash(Memory.wrap(in), 0L, in.length << 3, seed, new long[2]);
-  }
-
-  /**
-   * Returns a 128-bit hash of the input.
-   * Provided for compatibility with older version of MurmurHash3,
-   * but empty or null input now throws IllegalArgumentException.
-   * @param in int array
-   * @param seed A long valued seed.
-   * @return the hash
-   */
-  public static long[] hash(final int[] in, final long seed) {
-    if ((in == null) || (in.length == 0)) {
-      throw new IllegalArgumentException("Input in is empty or null.");
-    }
-    return hash(Memory.wrap(in), 0L, in.length << 2, seed, new long[2]);
-  }
-
-  /**
-   * Returns a 128-bit hash of the input.
-   * Provided for compatibility with older version of MurmurHash3,
-   * but empty or null input now throws IllegalArgumentException.
-   * @param in char array
-   * @param seed A long valued seed.
-   * @return the hash
-   */
-  public static long[] hash(final char[] in, final long seed) {
-    if ((in == null) || (in.length == 0)) {
-      throw new IllegalArgumentException("Input in is empty or null.");
-    }
-    return hash(Memory.wrap(in), 0L, in.length << 1, seed, new long[2]);
-  }
-
-  /**
-   * Returns a 128-bit hash of the input.
-   * Provided for compatibility with older version of MurmurHash3,
-   * but empty or null input now throws IllegalArgumentException.
-   * @param in byte array
-   * @param seed A long valued seed.
-   * @return the hash
-   */
-  public static long[] hash(final byte[] in, final long seed) {
-    if ((in == null) || (in.length == 0)) {
-      throw new IllegalArgumentException("Input in is empty or null.");
-    }
-    return hash(Memory.wrap(in), 0L, in.length, seed, new long[2]);
-  }
-
-  //Single primitive inputs
-
-  /**
-   * Returns a 128-bit hash of the input.
-   * Note the entropy of the resulting hash cannot be more than 64 bits.
-   * @param in a long
-   * @param seed A long valued seed.
-   * @param hashOut A long array of size 2
-   * @return the hash
-   */
-  public static long[] hash(final long in, final long seed, final long[] hashOut) {
-    final long h1 = seed ^ mixK1(in);
-    final long h2 = seed;
-    return finalMix128(h1, h2, 8, hashOut);
-  }
-
-  /**
-   * Returns a 128-bit hash of the input.
-   * Note the entropy of the resulting hash cannot be more than 64 bits.
-   * @param in a double
-   * @param seed A long valued seed.
-   * @param hashOut A long array of size 2
-   * @return the hash
-   */
-  public static long[] hash(final double in, final long seed, final long[] hashOut) {
-    final double d = (in == 0.0) ? 0.0 : in;    // canonicalize -0.0, 0.0
-    final long k1 = Double.doubleToLongBits(d); // canonicalize all NaN forms
-    final long h1 = seed ^ mixK1(k1);
-    final long h2 = seed;
-    return finalMix128(h1, h2, 8, hashOut);
-  }
-
-  /**
-   * Returns a 128-bit hash of the input.
-   * An empty or null input throws IllegalArgumentException.
-   * @param in a String
-   * @param seed A long valued seed.
-   * @param hashOut A long array of size 2
-   * @return the hash
-   */
-  public static long[] hash(final String in, final long seed, final long[] hashOut) {
-    if ((in == null) || (in.length() == 0)) {
-      throw new IllegalArgumentException("Input in is empty or null.");
-    }
-    final byte[] byteArr = in.getBytes(UTF_8);
-    return hash(Memory.wrap(byteArr), 0L, byteArr.length, seed, hashOut);
-  }
-
-  //The main API call
-
-  /**
-   * Returns a 128-bit hash of the input as a long array of size 2.
-   *
-   * @param mem The input on-heap Memory. Must be non-null and non-empty,
-   * otherwise throws IllegalArgumentException.
-   * @param offsetBytes the starting point within Memory.
-   * @param lengthBytes the total number of bytes to be hashed.
-   * @param seed A long valued seed.
-   * @param hashOut the size 2 long array for the resulting 128-bit hash
-   * @return the hash.
-   */
-  @SuppressWarnings("restriction")
-  public static long[] hash(final Memory mem, final long offsetBytes, final long lengthBytes,
-      final long seed, final long[] hashOut) {
-    if ((mem == null) || (mem.getCapacity() == 0L)) {
-      throw new IllegalArgumentException("Input mem is empty or null.");
-    }
-    final Object uObj = ((WritableMemory) mem).getArray();
-    if (uObj == null) {
-      throw new IllegalArgumentException("The backing resource of input mem is not on-heap.");
-    }
-    long cumOff = mem.getCumulativeOffset() + offsetBytes;
-
-    long h1 = seed;
-    long h2 = seed;
-    long rem = lengthBytes;
-
-    // Process the 128-bit blocks (the body) into the hash
-    while (rem >= 16L) {
-      final long k1 = unsafe.getLong(uObj, cumOff);     //0, 16, 32, ...
-      final long k2 = unsafe.getLong(uObj, cumOff + 8); //8, 24, 40, ...
-      cumOff += 16L;
-      rem -= 16L;
-
-      h1 ^= mixK1(k1);
-      h1 = Long.rotateLeft(h1, 27);
-      h1 += h2;
-      h1 = (h1 * 5) + 0x52dce729L;
-
-      h2 ^= mixK2(k2);
-      h2 = Long.rotateLeft(h2, 31);
-      h2 += h1;
-      h2 = (h2 * 5) + 0x38495ab5L;
-    }
-
-    // Get the tail (if any): 1 to 15 bytes
-    if (rem > 0L) {
-      long k1 = 0;
-      long k2 = 0;
-      switch ((int) rem) {
-        case 15: {
-          k2 ^= (unsafe.getByte(uObj, cumOff + 14) & 0xFFL) << 48;
-        }
-        //$FALL-THROUGH$
-        case 14: {
-          k2 ^= (unsafe.getShort(uObj, cumOff + 12) & 0xFFFFL) << 32;
-          k2 ^= (unsafe.getInt(uObj, cumOff + 8) & 0xFFFFFFFFL);
-          k1 = unsafe.getLong(uObj, cumOff);
-          break;
-        }
-
-        case 13: {
-          k2 ^= (unsafe.getByte(uObj, cumOff + 12) & 0xFFL) << 32;
-        }
-        //$FALL-THROUGH$
-        case 12: {
-          k2 ^= (unsafe.getInt(uObj, cumOff + 8) & 0xFFFFFFFFL);
-          k1 = unsafe.getLong(uObj, cumOff);
-          break;
-        }
-
-        case 11: {
-          k2 ^= (unsafe.getByte(uObj, cumOff + 10) & 0xFFL) << 16;
-        }
-        //$FALL-THROUGH$
-        case 10: {
-          k2 ^= (unsafe.getShort(uObj, cumOff +  8) & 0xFFFFL);
-          k1 = unsafe.getLong(uObj, cumOff);
-          break;
-        }
-
-        case  9: {
-          k2 ^= (unsafe.getByte(uObj, cumOff +  8) & 0xFFL);
-        }
-        //$FALL-THROUGH$
-        case  8: {
-          k1 = unsafe.getLong(uObj, cumOff);
-          break;
-        }
-
-        case  7: {
-          k1 ^= (unsafe.getByte(uObj, cumOff +  6) & 0xFFL) << 48;
-        }
-        //$FALL-THROUGH$
-        case  6: {
-          k1 ^= (unsafe.getShort(uObj, cumOff +  4) & 0xFFFFL) << 32;
-          k1 ^= (unsafe.getInt(uObj, cumOff) & 0xFFFFFFFFL);
-          break;
-        }
-
-        case  5: {
-          k1 ^= (unsafe.getByte(uObj, cumOff +  4) & 0xFFL) << 32;
-        }
-        //$FALL-THROUGH$
-        case  4: {
-          k1 ^= (unsafe.getInt(uObj, cumOff) & 0xFFFFFFFFL);
-          break;
-        }
-
-        case  3: {
-          k1 ^= (unsafe.getByte(uObj, cumOff +  2) & 0xFFL) << 16;
-        }
-        //$FALL-THROUGH$
-        case  2: {
-          k1 ^= (unsafe.getShort(uObj, cumOff) & 0xFFFFL);
-          break;
-        }
-
-        case  1: {
-          k1 ^= (unsafe.getByte(uObj, cumOff) & 0xFFL);
-          break;
-        }
-        //default: break; //can't happen
-      }
-
-      h1 ^= mixK1(k1);
-      h2 ^= mixK2(k2);
-    }
-    return finalMix128(h1, h2, lengthBytes, hashOut);
-  }
-
-  //--Helper methods----------------------------------------------------
-
-  /**
-   * Self mix of k1
-   *
-   * @param k1 input argument
-   * @return mix
-   */
-  private static long mixK1(long k1) {
-    k1 *= C1;
-    k1 = Long.rotateLeft(k1, 31);
-    k1 *= C2;
-    return k1;
-  }
-
-  /**
-   * Self mix of k2
-   *
-   * @param k2 input argument
-   * @return mix
-   */
-  private static long mixK2(long k2) {
-    k2 *= C2;
-    k2 = Long.rotateLeft(k2, 33);
-    k2 *= C1;
-    return k2;
-  }
-
-  /**
-   * Final self mix of h*.
-   *
-   * @param h input to final mix
-   * @return mix
-   */
-  private static long finalMix64(long h) {
-    h ^= h >>> 33;
-    h *= 0xff51afd7ed558ccdL;
-    h ^= h >>> 33;
-    h *= 0xc4ceb9fe1a85ec53L;
-    h ^= h >>> 33;
-    return h;
-  }
-
-  /**
-   * Finalization: Add the length into the hash and mix
-   * @param h1 intermediate hash
-   * @param h2 intermediate hash
-   * @param lengthBytes the length in bytes
-   * @param hashOut the output array of 2 longs
-   * @return hashOut
-   */
-  private static long[] finalMix128(long h1, long h2, final long lengthBytes, final long[] hashOut) {
-    h1 ^= lengthBytes;
-    h2 ^= lengthBytes;
-
-    h1 += h2;
-    h2 += h1;
-
-    h1 = finalMix64(h1);
-    h2 = finalMix64(h2);
-
-    h1 += h2;
-    h2 += h1;
-
-    hashOut[0] = h1;
-    hashOut[1] = h2;
-    return hashOut;
-  }
-
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Resource.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Resource.java
new file mode 100644
index 0000000..a7b27e2
--- /dev/null
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/Resource.java
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ *  Methods common to all memory access resources, including attributes like byte order and capacity.
+ *
+ * <p>The classes in this package are not thread-safe.</p>
+ *
+ * @author Lee Rhodes
+ */
+public interface Resource extends AutoCloseable {
+
+  static MemoryRequestServer defaultMemReqSvr = null; //policy choice
+
+  /**
+   * Closes this resource if this can be closed via <em>AutoCloseable</em>.
+   * If this operation completes without exceptions, this resource will be marked as <em>not alive</em>,
+   * and subsequent operations on this resource will fail with {@link IllegalStateException}.
+   *
+   * @apiNote This operation is not idempotent; that is, closing an already closed resource <em>always</em>
+   * results in an exception being thrown. This reflects a deliberate design choice: resource state transitions
+   * should be manifest in the client code; a failure in any of these transitions reveals a bug in the underlying
+   * application logic.
+   *
+   * @throws IllegalStateException if this Resource is not <em>valid</em>.
+   * @throws IllegalStateException if this method is not accessed from the owning thread.
+   * @throws UnsupportedOperationException if this resource is not {@link AutoCloseable}.
+   */
+  @Override
+  void close();
+
+  /**
+   * Returns true if the given object (<em>that</em>) is an instance of this class and has contents equal to
+   * this object.
+   * @param that the given Resource object
+   * @return true if the given object has equal contents to this object.
+   * @see #equalTo(long, Resource, long, long)
+   */
+  default boolean equalTo(Resource that) {
+    if (that == null || this.getCapacity() != that.getCapacity()) { return false; }
+    else { return equalTo(0, that, 0, that.getCapacity()); }
+  }
+
+  /**
+   * Returns true if the given Resource has equal contents to
+   * this object in the given range of bytes. This will also check two distinct ranges within the
+   * same object for equals.
+   * @param thisOffsetBytes the starting offset in bytes for this object.
+   * @param that the given Resource
+   * @param thatOffsetBytes the starting offset in bytes for the given Resource object
+   * @param lengthBytes the size of the range in bytes
+   * @return true if the given Resource object has equal contents to this object in the given range of bytes.
+   * @throws IllegalStateException if either resource is not <em>valid</em>.
+   * @throws MemoryBoundsException if there is a bounds violation.
+   */
+  boolean equalTo(long thisOffsetBytes, Resource that, long thatOffsetBytes, long lengthBytes);
+
+  /**
+   * Forces any changes made to the contents of this memory-mapped Resource to be written to the storage
+   * device described by the configured file descriptor.
+   *
+   * <p>If the file descriptor associated with this memory-mapped Resource resides on a local storage device then when
+   * this method returns, it is guaranteed that all changes made to this mapped Resource since it was created, or since
+   * this method was last invoked, will have been written to that device.</p>
+   *
+   * <p>If the file descriptor associated with this memory-mapped Resource does not reside on a local device then no
+   * such guarantee is made.</p>
+   *
+   * <p>If this memory-mapped Resource was not mapped in read/write mode
+   * ({@link java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this method may have no effect.
+   * In particular, this method has no effect for files mapped in read-only or private
+   * mapping modes. This method may or may not have an effect for implementation-specific mapping modes.</p>
+   *
+   * @throws IllegalStateException if this Resource is not <em>valid</em>.
+   * @throws IllegalStateException if this method is not accessed from the owning thread.
+   * @throws UnsupportedOperationException if this Resource is not memory-mapped, e.g. if {@code isMapped() == false}.
+   * @throws ReadOnlyException if this Resource is read-only.
+   * @throws RuntimeException if there is some other error writing the contents of this
+   * memory-mapped Resource to the associated storage device.
+   */
+  void force();
+
+  /**
+   * Gets the current ByteOrder.
+   * This may be different from the ByteOrder of the backing resource and {@link ByteOrder#nativeOrder()}
+   * @return the current ByteOrder.
+   */
+  ByteOrder getByteOrder();
+
+  /**
+   * Gets the capacity of this object in bytes
+   * @return the capacity of this object in bytes
+   */
+  long getCapacity();
+
+  /**
+   * Gets the MemoryRequestServer object, if set, for the below resources to request additional memory.
+   *
+   * <p>WritableMemory enables this for ByteBuffer, Heap and Direct Memory backed resources.</p>
+   *
+   * <p>WritableBuffer enables this for ByteBuffer backed resources. However, the object returned is in the form of
+   * a WritableMemory. To convert to WritableBuffer use asWritableBuffer(). To enable for Heap and Direct Buffer
+   * resources, use the WritableMemory to configure and then call asWritableBuffer().</p>
+   *
+   * <p>Map backed resources will always return null.</p>
+   *
+   * <p>The user must customize the actions of the MemoryRequestServer by
+   * implementing the MemoryRequestServer interface.</p>
+   *
+   * <p>For WritableMemory, to enable at runtime set your custom MemoryRequestServer using one of these methods:</p>
+   * <ul><li>{@link WritableMemory#allocateDirect(long, ByteOrder, MemoryRequestServer)}</li>
+   * <li>{@link WritableMemory#allocate(int, ByteOrder, MemoryRequestServer)}</li>
+   * <li>{@link WritableMemory#writableWrap(ByteBuffer, ByteOrder, MemoryRequestServer)}</li>
+   * </ul>
+   *
+   * <p>ForWritableBuffer, to enable at runtime set your custom MemoryRequestServer using the following method:</p>
+   * <ul>
+   * <li>{@link WritableBuffer#writableWrap(ByteBuffer, ByteOrder, MemoryRequestServer)}</li>
+   * </ul>
+   *
+   * <p>Simple implementation examples include the DefaultMemoryRequestServer in the main source tree, as well as
+   * the ExampleMemoryRequestServerTest and the use with ByteBuffer documented in the DruidIssue11544Test
+   * in the test source tree.</p>
+   *
+   * @return the MemoryRequestServer object or null.
+   */
+  MemoryRequestServer getMemoryRequestServer();
+
+  /**
+   * Returns the offset of address zero of this object relative to the base address of the
+   * backing resource. This does not include the object header for heap arrays nor the initial
+   * offset of a memory-mapped file.
+   * @return the offset of address zero of this object relative to the base address of the
+   * backing resource.
+   */
+  long getTotalOffset();
+
+  /**
+   * Returns true if this Memory is backed by a ByteBuffer.
+   * @return true if this Memory is backed by a ByteBuffer.
+   */
+  boolean isByteBufferResource();
+
+  /**
+   * Returns true if the Native ByteOrder is the same as the ByteOrder of the
+   * current Buffer or Memory and the same ByteOrder as the given byteOrder.
+   * @param byteOrder the given ByteOrder
+   * @return true if the Native ByteOrder is the same as the ByteOrder of the
+   * current Buffer or Memory and the same ByteOrder as the given byteOrder.
+   */
+  boolean isByteOrderCompatible(ByteOrder byteOrder);
+
+  /**
+   * If true, the backing resource is direct (off-heap) memory.
+   * This is the case for allocated direct memory, memory-mapped files,
+   * or from a wrapped ByteBuffer that was allocated direct.
+   * If false, the backing resource is the Java heap.
+   * @return true if the backing resource is direct (off-heap) memory.
+   */
+  boolean isDirectResource();
+
+  /**
+   * Returns true if this instance is a duplicate of a Buffer instance.
+   * @return true if this instance is a duplicate of a Buffer instance.
+   */
+  boolean isDuplicateBufferView();
+
+  /**
+   * Returns true if this object is backed by an on-heap primitive array or an on-heap ByteBuffer.
+   * @return true if this object is backed by an on-heap primitive array or an on-heap ByteBuffer.
+   */
+  boolean isHeapResource();
+
+  /**
+   * Tells whether or not the contents of this memory-mapped Resource is resident in physical memory.
+   *
+   * <p>A return value of {@code true} implies that it is highly likely that all of the data in this memory-mapped
+   * Resource is resident in physical memory and may therefore be accessed without incurring any virtual-memory page
+   * faults or I/O operations.</p>
+   *
+   * <p>A return value of {@code false} does not necessarily imply that all of the data in this memory-mapped Resource
+   * is not resident in physical memory.</p>
+   *
+   * <p>The returned value is a hint, rather than a guarantee, because the underlying operating system may have paged
+   * out some of this Resource's data by the time that an invocation of this method returns.</p>
+   *
+   * @return true if it is likely that all of the data in this memory-mapped Resource is resident in physical memory
+   *
+   * @throws IllegalStateException if this Resource is not <em>valid</em>.
+   * @throws IllegalStateException if this method is not accessed from the owning thread.
+   * @throws UnsupportedOperationException if this Resource is not memory-mapped, e.g. if {@code isMapped() == false}.
+   */
+  boolean isLoaded();
+
+  /**
+   * If true, this is a <i>Memory</i> or <i>WritableMemory</i> instance, which provides the Memory API.
+   * The Memory API is the principal API for this Memory Component.
+   * It provides a rich variety of direct manipulations of four types of resources:
+   * On-heap memory, direct (off-heap) memory, memory-mapped files, and ByteBuffers.
+   * If false, this is a <i>Buffer</i> or <i>WritableBuffer</i> instance, which provides the Buffer API.
+   *
+   * <p>The Buffer API is largely parallel to the Memory API except that it adds a positional API
+   * similar to that in <i>ByteBuffer</i>.  The positional API is a convenience when iterating over structured
+   * arrays, or buffering input or output streams (thus the name).</p>
+   *
+   * @return true if this is a <i>Memory</i> or <i>WritableMemory</i> instance, which provides the Memory API,
+   * otherwise this is a <i>Buffer</i> or <i>WritableBuffer</i> instance, which provides the Buffer API.
+   */
+  boolean isMemoryApi();
+
+  /**
+   * Returns true if the backing resource is a memory-mapped file.
+   * @return true if the backing resource is a memory-mapped file.
+   */
+  boolean isMemoryMappedResource();
+
+  /**
+   * If true, all put and get operations will assume the non-native ByteOrder.
+   * Otherwise, all put and get operations will assume the native ByteOrder.
+   * @return true, if all put and get operations will assume the non-native ByteOrder.
+   */
+  boolean isNonNativeOrder();
+
+  /**
+   * Returns true if this object or the backing resource is read-only.
+   * @return true if this object or the backing resource is read-only.
+   */
+  boolean isReadOnly();
+
+  /**
+   * Returns true if this instance is a region view of another Memory or Buffer
+   * @return true if this instance is a region view of another Memory or Buffer
+   */
+  boolean isRegionView();
+
+  /**
+   * Returns true if the backing resource of <i>this</i> is identical with the backing resource
+   * of <i>that</i>. The capacities must be the same.  If <i>this</i> is a region,
+   * the region offset must also be the same.
+   * @param that A different non-null Resource
+   * @return true if the backing resource of <i>this</i> is the same as the backing resource
+   * of <i>that</i>.
+   */
+  boolean isSameResource(Resource that);
+
+  /**
+   * Returns true if this object is valid and has not been closed.
+   * This is relevant only for direct (off-heap) memory and memory-mapped Files.
+   * @return true if this object is valid and has not been closed.
+   */
+  boolean isValid();
+
+  /**
+   * Loads the contents of this memory-mapped Resource into physical memory.
+   *
+   * <p>This method makes a best effort to ensure that, when it returns, this contents of the memory-mapped Resource is
+   * resident in physical memory. Invoking this method may cause some number of page faults and
+   * I/O operations to occur.</p>
+   *
+   * @throws IllegalStateException if this Resource is not <em>valid</em>.
+   * @throws IllegalStateException if this method is not accessed from the owning thread.
+   * @throws UnsupportedOperationException if this Resource is not memory-mapped, e.g. if {@code isMapped() == false}.
+   */
+  void load();
+
+  /**
+   * Sets the Default MemoryRequestServer
+   * @param memReqSvr the given MemoryRequestServer.
+   */
+  void setMemoryRequestServer(MemoryRequestServer memReqSvr);
+
+  /**
+   * Returns a description of this object with an optional formatted hex string of the data
+   * for the specified a range. Used primarily for testing.
+   * @param header a descriptive header
+   * @param offsetBytes offset bytes relative to this object start
+   * @param lengthBytes number of bytes to convert to a hex string
+// @param withData include output listing of byte data in the given range
+   * @return a formatted hex string in a human readable array
+   */
+  String toHexString(String header, long offsetBytes, int lengthBytes);
+
+  /**
+   * Returns the 64-bit hash of the sequence of bytes in this object specified by
+   * <i>offsetBytes</i>, <i>lengthBytes</i> and a <i>seed</i>.  Note that the sequence of bytes is
+   * always processed in the same order independent of endianness.
+   *
+   * @param offsetBytes the given offset in bytes to the first byte of the byte sequence.
+   * @param lengthBytes the given length in bytes of the byte sequence.
+   * @param seed the given long seed.
+   * @return the 64-bit hash of the sequence of bytes in this object specified by
+   * <i>offsetBytes</i> and <i>lengthBytes</i>.
+   */
+  long xxHash64(long offsetBytes, long lengthBytes, long seed);
+
+  /**
+   * Returns a 64-bit hash from a single long. This method has been optimized for speed when only
+   * a single hash of a long is required.
+   * @param in A long.
+   * @param seed A long valued seed.
+   * @return the hash.
+   */
+  long xxHash64(long in, long seed);
+
+}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableBuffer.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableBuffer.java
index b6aebe0..89c7845 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableBuffer.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableBuffer.java
@@ -29,6 +29,8 @@
 /**
  * Defines the writable API for relative positional access to a resource
  *
+ * <p>The classes in this package are not thread-safe.</p>
+ *
  * @author Lee Rhodes
  */
 public interface WritableBuffer extends Buffer {
@@ -364,11 +366,6 @@
   // NO ATOMIC METHODS
 
   //OTHER WRITE METHODS
-  /**
-   * Returns the primitive backing array, otherwise null.
-   * @return the primitive backing array, otherwise null.
-   */
-  Object getArray();
 
   /**
    * Clears all bytes of this Buffer from position to end to zero. The position will be set to end.
@@ -388,23 +385,4 @@
 
   //NO setBits(...)
 
-  //OTHER WRITABLE API METHODS
-  /**
-   * WritableBuffer enables this for ByteBuffer backed resources. However, the object returned is in the form of
-   * a WritableMemory. To convert to WritableBuffer use asWritableBuffer(). To enable for Heap and Direct Memory
-   * resources, use the WritableMemory to configure and then call asWritableBuffer().
-   * Map backed resources will always return null.
-   * Gets the MemoryRequestServer object, if set, for the above resources to request additional memory.
-   * The user must customize the actions of the MemoryRequestServer by
-   * implementing the MemoryRequestServer interface and set using the following method:
-   * <ul>
-   * <li>{@link WritableBuffer#writableWrap(ByteBuffer, ByteOrder, MemoryRequestServer)}</li>
-   * </ul>
-   * Simple implementation examples include the DefaultMemoryRequestServer in the main tree, as well as
-   * the ExampleMemoryRequestServerTest and the use with ByteBuffer documented in the DruidIssue11544Test
-   * in the test tree.
-   * @return the MemoryRequestServer object or null.
-   */
-  public MemoryRequestServer getMemoryRequestServer();
-
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMapHandle.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMapHandle.java
deleted file mode 100644
index 7cf9f18..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMapHandle.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory;
-
-/**
- * A Handle for a memory-mapped, writable file resource.
- * Joins a WritableHandle with an AutoCloseable WritableMap resource
- * Please read Javadocs for {@link Handle}.
- *
- * @author Roman Leventov
- * @author Lee Rhodes
- */
-public interface WritableMapHandle extends WritableMap, WritableHandle { }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMemory.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMemory.java
index cdc1635..e2dcdd0 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMemory.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMemory.java
@@ -28,11 +28,13 @@
 
 import org.apache.datasketches.memory.internal.BaseWritableMemoryImpl;
 import org.apache.datasketches.memory.internal.Prim;
-import org.apache.datasketches.memory.internal.UnsafeUtil;
+import org.apache.datasketches.memory.internal.ResourceImpl;
 
 /**
  * Defines the writable API for offset access to a resource.
  *
+ * <p>The classes in this package are not thread-safe.</p>
+ *
  * @author Lee Rhodes
  */
 public interface WritableMemory extends Memory {
@@ -84,10 +86,9 @@
    * Calling this method is equivalent to calling
    * {@link #writableMap(File, long, long, ByteOrder) writableMap(file, 0, file.length(), ByteOrder.nativeOrder())}.
    * @param file the given file to map. It must be non-null, with length &ge; 0, and writable.
-   * @return WritableMapHandle for managing the mapped Memory.
-   * Please read Javadocs for {@link Handle}.
+   * @return WritableMemory for managing the mapped Memory.
    */
-  static WritableMapHandle writableMap(File file) {
+  static WritableMemory writableMap(File file) {
     return writableMap(file, 0, file.length(), ByteOrder.nativeOrder());
   }
 
@@ -100,10 +101,9 @@
    * @param fileOffsetBytes the position in the given file in bytes. It must not be negative.
    * @param capacityBytes the size of the mapped Memory. It must not be negative.
    * @param byteOrder the byte order to be used for the given file. It must be non-null.
-   * @return WritableMapHandle for managing the mapped Memory.
-   * Please read Javadocs for {@link Handle}.
+   * @return WritableMemory for managing the mapped Memory.
    */
-  static WritableMapHandle writableMap(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) {
+  static WritableMemory writableMap(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) {
     Objects.requireNonNull(file, "file must be non-null.");
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
     if (!file.canWrite()) { throw new ReadOnlyException("file must be writable."); }
@@ -124,10 +124,9 @@
    * and to call <i>close()</i> when done.</p>
    *
    * @param capacityBytes the size of the desired memory in bytes. It must be &ge; 0.
-   * @return WritableHandle for this off-heap resource.
-   * Please read Javadocs for {@link Handle}.
+   * @return WritableMemory for this off-heap resource.
    */
-  static WritableHandle allocateDirect(long capacityBytes) {
+  static WritableMemory allocateDirect(long capacityBytes) {
     return allocateDirect(capacityBytes, ByteOrder.nativeOrder(), defaultMemReqSvr);
   }
 
@@ -143,10 +142,9 @@
    * @param byteOrder the given byte order. It must be non-null.
    * @param memReqSvr A user-specified MemoryRequestServer, which may be null.
    * This is a callback mechanism for a user client of direct memory to request more memory.
-   * @return WritableHandle for this off-heap resource.
-   * Please read Javadocs for {@link Handle}.
+   * @return WritableMemory for this off-heap resource.
    */
-  static WritableHandle allocateDirect(long capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
+  static WritableMemory allocateDirect(long capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
     negativeCheck(capacityBytes, "capacityBytes");
     return BaseWritableMemoryImpl.wrapDirect(capacityBytes, byteOrder, memReqSvr);
@@ -162,12 +160,12 @@
    * <li>Returned object's capacity = <i>capacityBytes</i></li>
    * </ul>
    *
-   * @param offsetBytes the starting offset with respect to this object. It must be &ge; 0.
+   * @param regionOffsetBytes the starting offset with respect to this object. It must be &ge; 0.
    * @param capacityBytes the capacity of the returned object in bytes. It must be &ge; 0.
    * @return a new <i>WritableMemory</i> representing the defined writable region.
    */
-  default WritableMemory writableRegion(long offsetBytes, long capacityBytes) {
-    return writableRegion(offsetBytes, capacityBytes, getTypeByteOrder());
+  default WritableMemory writableRegion(long regionOffsetBytes, long capacityBytes) {
+    return writableRegion(regionOffsetBytes, capacityBytes, getByteOrder());
   }
 
   /**
@@ -201,7 +199,7 @@
    * @return a new <i>WritableBuffer</i> with a view of this WritableMemory
    */
   default WritableBuffer asWritableBuffer() {
-    return asWritableBuffer(getTypeByteOrder());
+    return asWritableBuffer(getByteOrder());
   }
 
   /**
@@ -317,7 +315,7 @@
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
     negativeCheck(offsetBytes, "offsetBytes");
     negativeCheck(lengthBytes, "lengthBytes");
-    UnsafeUtil.checkBounds(offsetBytes, lengthBytes, array.length);
+    ResourceImpl.checkBounds(offsetBytes, lengthBytes, array.length);
     return BaseWritableMemoryImpl.wrapHeapArray(array, offsetBytes, lengthBytes, false, byteOrder, memReqSvr);
   }
 
@@ -329,7 +327,8 @@
   static WritableMemory writableWrap(boolean[] array) {
     Objects.requireNonNull(array, "array must be non-null");
     final long lengthBytes = array.length << Prim.BOOLEAN.shift();
-    return BaseWritableMemoryImpl.wrapHeapArray(array, 0, lengthBytes, false, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0, lengthBytes, false, ByteOrder.nativeOrder(),
+        defaultMemReqSvr);
   }
 
   /**
@@ -340,7 +339,8 @@
   static WritableMemory writableWrap(char[] array) {
     Objects.requireNonNull(array, "array must be non-null");
     final long lengthBytes = array.length << Prim.CHAR.shift();
-    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(),
+        defaultMemReqSvr);
   }
 
   /**
@@ -351,7 +351,8 @@
   static WritableMemory writableWrap(short[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final long lengthBytes = array.length << Prim.SHORT.shift();
-    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(),
+        defaultMemReqSvr);
   }
 
   /**
@@ -362,7 +363,8 @@
   static WritableMemory writableWrap(int[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final long lengthBytes = array.length << Prim.INT.shift();
-    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(),
+        defaultMemReqSvr);
   }
 
   /**
@@ -373,7 +375,8 @@
   static WritableMemory writableWrap(long[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final long lengthBytes = array.length << Prim.LONG.shift();
-    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(),
+        defaultMemReqSvr);
   }
 
   /**
@@ -384,7 +387,8 @@
   static WritableMemory writableWrap(float[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final long lengthBytes = array.length << Prim.FLOAT.shift();
-    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(),
+        defaultMemReqSvr);
   }
 
   /**
@@ -395,7 +399,8 @@
   static WritableMemory writableWrap(double[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final long lengthBytes = array.length << Prim.DOUBLE.shift();
-    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(),
+        defaultMemReqSvr);
   }
   //END OF CONSTRUCTOR-TYPE METHODS
 
@@ -450,7 +455,7 @@
 
   /**
    * Encodes characters from the given CharSequence into UTF-8 bytes and puts them into this
-   * <i>WritableMemory</i> begining at the given offsetBytes.
+   * <i>WritableMemory</i> beginning at the given offsetBytes.
    * This is specifically designed to reduce the production of intermediate objects (garbage),
    * thus significantly reducing pressure on the JVM Garbage Collector.
    * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
@@ -542,40 +547,7 @@
    */
   void putShortArray(long offsetBytes, short[] srcArray, int srcOffsetShorts, int lengthShorts);
 
-  //Atomic Methods
-  /**
-   * Atomically adds the given value to the long located at offsetBytes.
-   * @param offsetBytes offset bytes relative to this Memory start
-   * @param delta the amount to add
-   * @return the the previous value
-   */
-  long getAndAddLong(long offsetBytes, long delta);
-
-  /**
-   * Atomically sets the current value at the memory location to the given updated value
-   * if and only if the current value {@code ==} the expected value.
-   * @param offsetBytes offset bytes relative to this Memory start
-   * @param expect the expected value
-   * @param update the new value
-   * @return {@code true} if successful. False return indicates that
-   * the current value at the memory location was not equal to the expected value.
-   */
-  boolean compareAndSwapLong(long offsetBytes, long expect, long update);
-
-  /**
-   * Atomically exchanges the given value with the current value located at offsetBytes.
-   * @param offsetBytes offset bytes relative to this Memory start
-   * @param newValue new value
-   * @return the previous value
-   */
-  long getAndSetLong(long offsetBytes, long newValue);
-
   //OTHER WRITE METHODS
-  /**
-   * Returns the primitive backing array, otherwise null.
-   * @return the primitive backing array, otherwise null.
-   */
-  Object getArray();
 
   /**
    * Clears all bytes of this Memory to zero
@@ -617,23 +589,4 @@
    */
   void setBits(long offsetBytes, byte bitMask);
 
-
-  //OTHER WRITABLE API METHODS
-  /**
-   * WritableMemory enables this for ByteBuffer, Heap and Direct Memory backed resources.
-   * Map backed resources will always return null.
-   * Gets the MemoryRequestServer object, if set, for the above resources to request additional memory.
-   * The user must customize the actions of the MemoryRequestServer by
-   * implementing the MemoryRequestServer interface and set using one of these methods:
-   * <ul><li>{@link WritableMemory#allocateDirect(long, ByteOrder, MemoryRequestServer)}</li>
-   * <li>{@link WritableMemory#allocate(int, ByteOrder, MemoryRequestServer)}</li>
-   * <li>{@link WritableMemory#writableWrap(ByteBuffer, ByteOrder, MemoryRequestServer)}</li>
-   * </ul>
-   * Simple implementation examples include the DefaultMemoryRequestServer in the main tree, as well as
-   * the ExampleMemoryRequestServerTest and the use with ByteBuffer documented in the DruidIssue11544Test
-   * in the test tree.
-   * @return the MemoryRequestServer object or null.
-   */
-  MemoryRequestServer getMemoryRequestServer();
-
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AccessByteBuffer.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AccessByteBuffer.java
index 2ec9020..9319e82 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AccessByteBuffer.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AccessByteBuffer.java
@@ -47,8 +47,9 @@
       UnsafeUtil.getFieldOffset(java.nio.ByteBuffer.class, "offset");
 
   final long nativeBaseOffset;
+  final long initialCumOffset;
   final long capacityBytes;
-  final long regionOffset;
+  final long offsetBytes;
   final Object unsafeObj;
   final boolean resourceReadOnly;
   final ByteOrder byteOrder; //not used externally, here for reference.
@@ -65,14 +66,17 @@
     if (direct) {
       nativeBaseOffset = ((sun.nio.ch.DirectBuffer) byteBuf).address();
       unsafeObj = null;
-      regionOffset = 0L; //address() is already adjusted for direct slices, so regionOffset = 0
+      offsetBytes = 0L; //address() is already adjusted for direct slices, so offset = 0
+      initialCumOffset = nativeBaseOffset;
     } else {
       nativeBaseOffset = 0L;
       // ByteBuffer.arrayOffset() and ByteBuffer.array() throw ReadOnlyBufferException if
-      // ByteBuffer is read-only. This uses reflection for both writable and read-only cases.
-      // Includes the slice() offset for heap.
-      regionOffset = unsafe.getInt(byteBuf, BYTE_BUFFER_OFFSET_FIELD_OFFSET);
+      // ByteBuffer is read-only, so this uses reflection for both writable and read-only cases.
+      // OffsetBytes includes the slice() offset for heap.  The original array is still there because
+      // this is a view.
+      offsetBytes = unsafe.getInt(byteBuf, BYTE_BUFFER_OFFSET_FIELD_OFFSET);
       unsafeObj = unsafe.getObject(byteBuf, BYTE_BUFFER_HB_FIELD_OFFSET);
+      initialCumOffset = UnsafeUtil.getArrayBaseOffset(unsafeObj.getClass()) + offsetBytes;
     }
   }
 
@@ -82,11 +86,11 @@
    * : wrap(...). See LICENSE.
    */
   static ByteBuffer getDummyReadOnlyDirectByteBuffer(final long address, final int capacity) {
-    final ByteBuffer buf = ZERO_READ_ONLY_DIRECT_BYTE_BUFFER.duplicate();
-    unsafe.putLong(buf, NIO_BUFFER_ADDRESS_FIELD_OFFSET, address);
-    unsafe.putInt(buf, NIO_BUFFER_CAPACITY_FIELD_OFFSET, capacity);
-    buf.limit(capacity);
-    return buf;
+    final ByteBuffer byteBuf = ZERO_READ_ONLY_DIRECT_BYTE_BUFFER.duplicate();
+    unsafe.putLong(byteBuf, NIO_BUFFER_ADDRESS_FIELD_OFFSET, address);
+    unsafe.putInt(byteBuf, NIO_BUFFER_CAPACITY_FIELD_OFFSET, capacity);
+    byteBuf.limit(capacity);
+    return byteBuf;
   }
 
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java
index ae649ef..b2b1992 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java
@@ -46,16 +46,13 @@
    * @param capacityBytes the the requested capacity of off-heap memory. Cannot be zero.
    */
   AllocateDirect(final long capacityBytes) {
-    final boolean pageAligned = NioBits.isPageAligned();
-    final long pageSize = NioBits.pageSize();
+    final boolean pageAligned = VirtualMachineMemory.getIsPageAligned();
+    final long pageSize = getPageSize();
     final long allocationSize = capacityBytes + (pageAligned ? pageSize : 0);
-    NioBits.reserveMemory(allocationSize, capacityBytes);
-
     final long nativeAddress;
     try {
       nativeAddress = unsafe.allocateMemory(allocationSize);
     } catch (final OutOfMemoryError err) {
-      NioBits.unreserveMemory(allocationSize, capacityBytes);
       throw new RuntimeException(err);
     }
     if (pageAligned && ((nativeAddress % pageSize) != 0)) {
@@ -64,22 +61,20 @@
     } else {
       nativeBaseOffset = nativeAddress;
     }
-    deallocator = new Deallocator(nativeAddress, allocationSize, capacityBytes);
+    deallocator = new Deallocator(nativeAddress);
     cleaner = new MemoryCleaner(this, deallocator);
   }
 
-  boolean doClose() {
+  public void close() {
     try {
       if (deallocator.deallocate(false)) {
         // This Cleaner.clean() call effectively just removes the Cleaner from the internal linked
         // list of all cleaners. It will delegate to Deallocator.deallocate() which will be a no-op
         // because the valid state is already changed.
         cleaner.clean();
-        return true;
       }
-      return false;
     } finally {
-      BaseStateImpl.reachabilityFence(this);
+      ResourceImpl.reachabilityFence(this);
     }
   }
 
@@ -87,24 +82,21 @@
     return nativeBaseOffset;
   }
 
-  StepBoolean getValid() {
+  public static int getPageSize() {
+    return unsafe.pageSize();
+  }
+
+  public StepBoolean getValid() {
     return deallocator.getValid();
   }
 
-  static final class Deallocator implements Runnable {
+  private static final class Deallocator implements Runnable {
     //This is the only place the actual native address is kept for use by unsafe.freeMemory();
     private final long nativeAddress;
-    private final long allocationSize;
-    private final long capacity;
     private final StepBoolean valid = new StepBoolean(true); //only place for this
 
-    Deallocator(final long nativeAddress, final long allocationSize, final long capacity) {
-      BaseStateImpl.currentDirectMemoryAllocations_.incrementAndGet();
-      BaseStateImpl.currentDirectMemoryAllocated_.addAndGet(capacity);
+    Deallocator(final long nativeAddress) {
       this.nativeAddress = nativeAddress;
-      this.allocationSize = allocationSize;
-      this.capacity = capacity;
-      assert (nativeAddress != 0);
     }
 
     StepBoolean getValid() {
@@ -112,20 +104,17 @@
     }
 
     @Override
-    public void run() {
+    public void run() throws IllegalStateException {
       deallocate(true);
     }
 
-    boolean deallocate(final boolean calledFromCleaner) {
+    boolean deallocate(final boolean calledFromCleaner) throws IllegalStateException {
       if (valid.change()) {
         if (calledFromCleaner) {
           // Warn about non-deterministic resource cleanup.
-          LOG.warning("A WritableHandle was not closed manually");
+          LOG.warning("A direct resource was not closed explicitly");
         }
         unsafe.freeMemory(nativeAddress);
-        NioBits.unreserveMemory(allocationSize, capacity);
-        BaseStateImpl.currentDirectMemoryAllocations_.decrementAndGet();
-        BaseStateImpl.currentDirectMemoryAllocated_.addAndGet(-capacity);
         return true;
       }
       return false;
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java
deleted file mode 100644
index 6126fac..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.logging.Logger;
-
-import org.apache.datasketches.memory.Map;
-import org.apache.datasketches.memory.MemoryCloseException;
-
-import sun.nio.ch.FileChannelImpl;
-
-/**
- * Allocates direct memory used to memory map files for read operations.
- * (including those &gt; 2GB).
- *
- * <p>To understand how it works, reference native code for map0, unmap0:
- * <a href="http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/solaris/native/sun/nio/ch/FileChannelImpl.c">
- * FileChannelImpl.c</a></p>
- *
- * <p>To understand how it works, reference native code for load0(), isLoaded0(), and force0():
- * <a href="http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/solaris/native/java/nio/MappedByteBuffer.c">
- * MappedByteBuffer.c</a></p>
- *
- * @author Roman Leventov
- * @author Lee Rhodes
- * @author Praveenkumar Venkatesan
- */
-@SuppressWarnings("restriction")
-class AllocateDirectMap implements Map {
-  static final Logger LOG = Logger.getLogger(AllocateDirectMap.class.getCanonicalName());
-
-  private static final int MAP_RO = 0;
-  private static final int MAP_RW = 1;
-
-  private static final Method FILE_CHANNEL_IMPL_MAP0_METHOD;
-  static final Method FILE_CHANNEL_IMPL_UNMAP0_METHOD;
-
-  private static final Method MAPPED_BYTE_BUFFER_LOAD0_METHOD;
-  private static final Method MAPPED_BYTE_BUFFER_ISLOADED0_METHOD;
-  static final Method MAPPED_BYTE_BUFFER_FORCE0_METHOD;
-
-  static {
-    try { //The FileChannelImpl methods map0 and unmap0 still exist in 16
-      FILE_CHANNEL_IMPL_MAP0_METHOD = FileChannelImpl.class
-          .getDeclaredMethod("map0", int.class, long.class, long.class); //JDK14 add boolean.class
-      FILE_CHANNEL_IMPL_MAP0_METHOD.setAccessible(true);
-
-      FILE_CHANNEL_IMPL_UNMAP0_METHOD = FileChannelImpl.class
-          .getDeclaredMethod("unmap0", long.class, long.class); //OK through jDK16
-      FILE_CHANNEL_IMPL_UNMAP0_METHOD.setAccessible(true);
-
-
-      //The MappedByteBuffer methods load0, isLoaded0 and force0 are removed in 15
-      MAPPED_BYTE_BUFFER_LOAD0_METHOD = MappedByteBuffer.class
-          .getDeclaredMethod("load0", long.class, long.class); //JDK15 removed
-      MAPPED_BYTE_BUFFER_LOAD0_METHOD.setAccessible(true);
-
-      MAPPED_BYTE_BUFFER_ISLOADED0_METHOD = MappedByteBuffer.class
-          .getDeclaredMethod("isLoaded0", long.class, long.class, int.class); //JDK15 removed
-      MAPPED_BYTE_BUFFER_ISLOADED0_METHOD.setAccessible(true);
-
-      MAPPED_BYTE_BUFFER_FORCE0_METHOD = MappedByteBuffer.class
-          .getDeclaredMethod("force0", FileDescriptor.class, long.class, long.class); //JDK15 removed
-      MAPPED_BYTE_BUFFER_FORCE0_METHOD.setAccessible(true);
-    } catch (final SecurityException | NoSuchMethodException e) {
-      throw new RuntimeException("Could not reflect static methods: " + e);
-    }
-  }
-
-  private final Deallocator deallocator;
-  private final MemoryCleaner cleaner;
-
-  final long capacityBytes;
-  final RandomAccessFile raf;
-  final long nativeBaseOffset;
-  final boolean resourceReadOnly;
-
-  //called from AllocateDirectWritableMap constructor
-  AllocateDirectMap(final File file, final long fileOffsetBytes, final long capacityBytes,
-      final boolean localReadOnly) {
-    this.capacityBytes = capacityBytes;
-    resourceReadOnly = isFileReadOnly(file);
-    final long fileLength = file.length();
-    if ((localReadOnly || resourceReadOnly) && fileOffsetBytes + capacityBytes > fileLength) {
-      throw new IllegalArgumentException(
-          "Read-only mode and requested map length is greater than current file length: "
-          + "Requested Length = " + (fileOffsetBytes + capacityBytes)
-          + ", Current File Length = " + fileLength);
-    }
-    raf = mapper(file, fileOffsetBytes, capacityBytes, resourceReadOnly);
-    nativeBaseOffset = map(raf.getChannel(), resourceReadOnly, fileOffsetBytes, capacityBytes);
-    deallocator = new Deallocator(nativeBaseOffset, capacityBytes, raf);
-    cleaner = new MemoryCleaner(this, deallocator);
-  }
-
-  //Map Interface
-
-  @Override
-  public void load() {
-    madvise();
-    // Performance optimization. Read a byte from each page to bring it into memory.
-    final int ps = NioBits.pageSize();
-    final int count = NioBits.pageCount(capacityBytes);
-    long offset = nativeBaseOffset;
-    for (int i = 0; i < count; i++) {
-      unsafe.getByte(offset);
-      offset += ps;
-    }
-  }
-
-  @Override
-  public boolean isLoaded() {
-    try {
-      final int pageCount = NioBits.pageCount(capacityBytes);
-      return (boolean) MAPPED_BYTE_BUFFER_ISLOADED0_METHOD
-          //isLoaded0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is not modified
-          .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
-              nativeBaseOffset,
-              capacityBytes,
-              pageCount);
-    } catch (final  IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-      throw new RuntimeException(
-              String.format("Encountered %s exception while loading", e.getClass()));
-    }
-  }
-  // End Map Interface
-
-  @Override
-  public void close() {
-    doClose("AllocateDirectMap");
-  }
-
-  boolean doClose(final String resource) {
-    try {
-      if (deallocator.deallocate(false)) {
-        // This Cleaner.clean() call effectively just removes the Cleaner from the internal linked
-        // list of all cleaners. It will delegate to Deallocator.deallocate() which will be a no-op
-        // because the valid state is already changed.
-        cleaner.clean();
-        return true;
-      }
-      return false;
-    } catch (final Exception e) {
-        throw new MemoryCloseException(resource);
-    } finally {
-      BaseStateImpl.reachabilityFence(this);
-    }
-  }
-
-  StepBoolean getValid() {
-    return deallocator.getValid();
-  }
-
-  // Private methods
-  /**
-   * called by load(). Calls the native method load0 in MappedByteBuffer.java, implemented
-   * in MappedByteBuffer.c. See reference at top of class. load0 allows setting a mapping length
-   * of greater than 2GB.
-   */
-  private void madvise() {
-    try {
-      MAPPED_BYTE_BUFFER_LOAD0_METHOD
-        //load0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is not modified
-        .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
-            nativeBaseOffset,
-            capacityBytes);
-    } catch (final  IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-      throw new RuntimeException(
-          String.format("Encountered %s exception while loading", e.getClass()));
-    }
-  }
-
-  //Does the actual mapping work, resourceReadOnly must already be set
-  private static RandomAccessFile mapper(final File file, final long fileOffset,
-      final long capacityBytes, final boolean resourceReadOnly)  {
-
-    final String mode = resourceReadOnly ? "r" : "rw";
-    final RandomAccessFile raf;
-    try {
-      raf = new RandomAccessFile(file, mode);
-      if (fileOffset + capacityBytes > raf.length()) {
-        raf.setLength(fileOffset + capacityBytes);
-      }
-    } catch (final IOException e) {
-      throw new RuntimeException(e);
-    }
-    return raf;
-  }
-
-  /**
-   * Creates a mapping of the FileChannel starting at position and of size length to pages
-   * in the OS. This may throw OutOfMemory error if you have exhausted memory.
-   * You can try to force garbage collection and re-attempt.
-   *
-   * <p>map0 is a native method of FileChannelImpl.java implemented in FileChannelImpl.c.
-   * See reference at top of class.</p>
-   *
-   * @param fileChannel the FileChannel
-   * @param position the offset in bytes into the FileChannel
-   * @param lengthBytes the length in bytes
-   * @return the native base offset address
-   * @throws RuntimeException Encountered an exception while mapping
-   */
-  private static long map(final FileChannel fileChannel, final boolean resourceReadOnly,
-      final long position, final long lengthBytes) {
-    final int pagePosition = (int) (position % unsafe.pageSize());
-    final long mapPosition = position - pagePosition;
-    final long mapSize = lengthBytes + pagePosition;
-    final int mapMode = resourceReadOnly ? MAP_RO : MAP_RW;
-    //final boolean isSync = true; //required as of JDK14, but it is more complex
-    try {
-      final long nativeBaseOffset = //JDK14 add isSync
-        (long) FILE_CHANNEL_IMPL_MAP0_METHOD.invoke(fileChannel, mapMode, mapPosition, mapSize);
-      return nativeBaseOffset;
-    } catch (final InvocationTargetException e) {
-      throw new RuntimeException("Exception while mapping", e.getTargetException());
-    } catch (final IllegalAccessException e) {
-      throw new RuntimeException("Exception while mapping", e);
-    }
-  }
-
-  public static boolean isFileReadOnly(final File file) {
-    return (!file.canWrite());
-  }
-
-  private static final class Deallocator implements Runnable {
-    private final RandomAccessFile myRaf;
-    private final FileChannel myFc;
-    //This is the only place the actual native offset is kept for use by unsafe.freeMemory();
-    private final long actualNativeBaseOffset;
-    private final long myCapacity;
-    private final StepBoolean valid = new StepBoolean(true); //only place for this
-
-    Deallocator(final long nativeBaseOffset, final long capacityBytes,
-        final RandomAccessFile raf) {
-      BaseStateImpl.currentDirectMemoryMapAllocations_.incrementAndGet();
-      BaseStateImpl.currentDirectMemoryMapAllocated_.addAndGet(capacityBytes);
-      myRaf = raf;
-      assert myRaf != null;
-      myFc = myRaf.getChannel();
-      actualNativeBaseOffset = nativeBaseOffset;
-      assert actualNativeBaseOffset != 0;
-      myCapacity = capacityBytes;
-      assert myCapacity != 0;
-    }
-
-    StepBoolean getValid() {
-      return valid;
-    }
-
-    @Override
-    public void run() {
-      deallocate(true);
-    }
-
-    boolean deallocate(final boolean calledFromCleaner) {
-      if (valid.change()) {
-        if (calledFromCleaner) {
-          // Warn about non-deterministic resource cleanup.
-          LOG.warning("A WritableMapHandleImpl was not closed manually");
-        }
-        try {
-          unmap();
-        }
-        finally {
-          BaseStateImpl.currentDirectMemoryMapAllocations_.decrementAndGet();
-          BaseStateImpl.currentDirectMemoryMapAllocated_.addAndGet(-myCapacity);
-        }
-        return true;
-      }
-      return false;
-    }
-
-    /**
-     * Removes existing mapping.  <i>unmap0</i> is a native method in FileChannelImpl.c. See
-     * reference at top of class.
-     */
-    private void unmap() throws RuntimeException {
-      try {
-        FILE_CHANNEL_IMPL_UNMAP0_METHOD.invoke(myFc, actualNativeBaseOffset, myCapacity);
-        myRaf.close();
-      } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException | IOException e) {
-        throw new RuntimeException(
-            String.format("Encountered %s exception while freeing memory", e.getClass()));
-      }
-    }
-  } //End of class Deallocator
-
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java
index 6335076..41fb014 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java
@@ -19,36 +19,123 @@
 
 package org.apache.datasketches.memory.internal;
 
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
+import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
 
-import org.apache.datasketches.memory.ReadOnlyException;
-import org.apache.datasketches.memory.WritableMap;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.logging.Logger;
+
+import sun.nio.ch.FileChannelImpl;
 
 /**
- * Allocates direct memory used to memory map files for write operations
+ * Allocates direct memory used to memory map files for read or write operations.
  * (including those &gt; 2GB).
  *
- * @author Lee Rhodes
+ * <p>To understand how it works, reference native code for map0, unmap0:
+ * <a href="http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/solaris/native/sun/nio/ch/FileChannelImpl.c">
+ * FileChannelImpl.c</a></p>
+ *
+ * <p>To understand how it works, reference native code for load0(), isLoaded0(), and force0():
+ * <a href="http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/solaris/native/java/nio/MappedByteBuffer.c">
+ * MappedByteBuffer.c</a></p>
+ *
  * @author Roman Leventov
+ * @author Lee Rhodes
  * @author Praveenkumar Venkatesan
  */
-//Called from WritableMemoryImpl, implements combo of WritableMemoryImpl with WritableMap resource
-final class AllocateDirectWritableMap extends AllocateDirectMap implements WritableMap {
+@SuppressWarnings("restriction")
+class AllocateDirectWritableMap {
+  static final Logger LOG = Logger.getLogger(AllocateDirectWritableMap.class.getCanonicalName());
 
-  AllocateDirectWritableMap(final File file, final long fileOffsetBytes,
-      final long capacityBytes, final boolean localReadOnly) {
-    super(file, fileOffsetBytes, capacityBytes, localReadOnly);
+  private static final int MAP_RO = 0;
+  private static final int MAP_RW = 1;
+
+  private static final Method FILE_CHANNEL_IMPL_MAP0_METHOD;
+  static final Method FILE_CHANNEL_IMPL_UNMAP0_METHOD;
+
+  private static final Method MAPPED_BYTE_BUFFER_LOAD0_METHOD;
+  private static final Method MAPPED_BYTE_BUFFER_ISLOADED0_METHOD;
+  static final Method MAPPED_BYTE_BUFFER_FORCE0_METHOD;
+  private static int pageSize = unsafe.pageSize();
+
+  static {
+    try { //The FileChannelImpl methods map0 and unmap0 still exist in 16
+      FILE_CHANNEL_IMPL_MAP0_METHOD = FileChannelImpl.class
+          .getDeclaredMethod("map0", int.class, long.class, long.class); //JDK14 add boolean.class
+      FILE_CHANNEL_IMPL_MAP0_METHOD.setAccessible(true);
+
+      FILE_CHANNEL_IMPL_UNMAP0_METHOD = FileChannelImpl.class
+          .getDeclaredMethod("unmap0", long.class, long.class); //OK through jDK16
+      FILE_CHANNEL_IMPL_UNMAP0_METHOD.setAccessible(true);
+
+
+      //The MappedByteBuffer methods load0, isLoaded0 and force0 are removed in 15
+      MAPPED_BYTE_BUFFER_LOAD0_METHOD = MappedByteBuffer.class
+          .getDeclaredMethod("load0", long.class, long.class); //JDK15 removed
+      MAPPED_BYTE_BUFFER_LOAD0_METHOD.setAccessible(true);
+
+      MAPPED_BYTE_BUFFER_ISLOADED0_METHOD = MappedByteBuffer.class
+          .getDeclaredMethod("isLoaded0", long.class, long.class, int.class); //JDK15 removed
+      MAPPED_BYTE_BUFFER_ISLOADED0_METHOD.setAccessible(true);
+
+      MAPPED_BYTE_BUFFER_FORCE0_METHOD = MappedByteBuffer.class
+          .getDeclaredMethod("force0", FileDescriptor.class, long.class, long.class); //JDK15 removed
+      MAPPED_BYTE_BUFFER_FORCE0_METHOD.setAccessible(true);
+    } catch (final SecurityException | NoSuchMethodException e) {
+      throw new RuntimeException("Could not reflect static methods: " + e);
+    }
   }
 
-  //Added by WritableMap Interface
+  private final Deallocator deallocator;
+  private final MemoryCleaner cleaner;
 
-  @Override
-  public void force() {
-    if (resourceReadOnly) {
-      throw new ReadOnlyException("MemoryImpl Mapped File is Read Only.");
+  private final File file;
+  final long capacityBytes;
+  final RandomAccessFile raf;
+  final long nativeBaseOffset;
+  final boolean resourceReadOnly;
+
+  AllocateDirectWritableMap(final File file, final long fileOffsetBytes, final long capacityBytes,
+      final boolean localReadOnly) {
+    this.file = file;
+    this.capacityBytes = capacityBytes;
+    resourceReadOnly = isFileReadOnly(file);
+    final long fileLength = file.length();
+    if ((localReadOnly || resourceReadOnly) && fileOffsetBytes + capacityBytes > fileLength) {
+      throw new IllegalArgumentException(
+          "Read-only mode and requested map length is greater than current file length: "
+          + "Requested Length = " + (fileOffsetBytes + capacityBytes)
+          + ", Current File Length = " + fileLength);
     }
+    raf = mapper(file, fileOffsetBytes, capacityBytes, resourceReadOnly);
+    nativeBaseOffset = map(raf.getChannel(), resourceReadOnly, fileOffsetBytes, capacityBytes);
+    deallocator = new Deallocator(nativeBaseOffset, capacityBytes, raf);
+    cleaner = new MemoryCleaner(this, deallocator);
+  }
+
+  public void close() {
+    try {
+      if (deallocator.deallocate(false)) {
+        // This Cleaner.clean() call effectively just removes the Cleaner from the internal linked
+        // list of all cleaners. It will delegate to Deallocator.deallocate() which will be a no-op
+        // because the valid state is already changed.
+        cleaner.clean();
+      }
+
+    } catch (final Exception e) { throw new IllegalStateException("Attempted close of Memory-Mapped File: "
+        + file.getName() + " " + e);
+    } finally {
+      ResourceImpl.reachabilityFence(this);
+    }
+  }
+
+  public void force() {
     try {
       MAPPED_BYTE_BUFFER_FORCE0_METHOD
           //force0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is not modified
@@ -57,7 +144,167 @@
               nativeBaseOffset,
               capacityBytes);
     } catch (final IOException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-      throw new RuntimeException(String.format("Encountered %s exception in force. " + e.getClass()));
+      throw new RuntimeException(String.format("Encountered %s exception in force. " + e.toString()));
     }
   }
+
+  public StepBoolean getValid() {
+    return deallocator.getValid();
+  }
+
+  public static boolean isFileReadOnly(final File file) {
+    return (!file.canWrite());
+  }
+
+  public boolean isLoaded() {
+    try {
+      return (boolean) MAPPED_BYTE_BUFFER_ISLOADED0_METHOD
+          //isLoaded0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is not modified
+          .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
+              nativeBaseOffset,
+              capacityBytes,
+              pageCount(capacityBytes));
+    } catch (final  IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(
+              String.format("Encountered %s exception while loading", e.getClass()));
+    }
+  }
+
+  public void load() {
+    madvise();
+    // Performance optimization. Read a byte from each page to bring it into memory.
+    final int count = pageCount(capacityBytes);
+    long offset = nativeBaseOffset;
+    for (int i = 0; i < count; i++) {
+      unsafe.getByte(offset);
+      offset += pageSize;
+    }
+  }
+
+  // Private methods
+  /**
+   * called by load(). Calls the native method load0 in MappedByteBuffer.java, implemented
+   * in MappedByteBuffer.c. See reference at top of class. load0 allows setting a mapping length
+   * of greater than 2GB.
+   */
+  private void madvise() {
+    try {
+      MAPPED_BYTE_BUFFER_LOAD0_METHOD
+        //load0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is not modified
+        .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
+            nativeBaseOffset,
+            capacityBytes);
+    } catch (final  IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(
+          String.format("Encountered %s exception while loading", e.getClass()));
+    }
+  }
+
+  private static int pageCount(final long bytes) {
+    return (int)((bytes + pageSize) - 1L) / pageSize;
+  }
+
+  //Does the actual mapping work, resourceReadOnly must already be set
+  private static RandomAccessFile mapper(final File file, final long fileOffset,
+      final long capacityBytes, final boolean resourceReadOnly)  {
+
+    final String mode = resourceReadOnly ? "r" : "rw";
+    final RandomAccessFile raf;
+    try {
+      raf = new RandomAccessFile(file, mode);
+      if (fileOffset + capacityBytes > raf.length()) {
+        raf.setLength(fileOffset + capacityBytes);
+      }
+    } catch (final IOException e) {
+      throw new RuntimeException(e);
+    }
+    return raf;
+  }
+
+  /**
+   * Creates a mapping of the FileChannel starting at position and of size length to pages
+   * in the OS. This may throw OutOfMemory error if you have exhausted memory.
+   * You can try to force garbage collection and re-attempt.
+   *
+   * <p>map0 is a native method of FileChannelImpl.java implemented in FileChannelImpl.c.
+   * See reference at top of class.</p>
+   *
+   * @param fileChannel the FileChannel
+   * @param position the offset in bytes into the FileChannel
+   * @param lengthBytes the length in bytes
+   * @return the native base offset address
+   * @throws RuntimeException Encountered an exception while mapping
+   */
+  private static long map(final FileChannel fileChannel, final boolean resourceReadOnly,
+      final long position, final long lengthBytes) {
+    final int pagePosition = (int) (position % unsafe.pageSize());
+    final long mapPosition = position - pagePosition;
+    final long mapSize = lengthBytes + pagePosition;
+    final int mapMode = resourceReadOnly ? MAP_RO : MAP_RW;
+    //final boolean isSync = true; //required as of JDK14, but it is more complex
+    try {
+      final long nativeBaseOffset = //JDK14 add isSync
+        (long) FILE_CHANNEL_IMPL_MAP0_METHOD.invoke(fileChannel, mapMode, mapPosition, mapSize);
+      return nativeBaseOffset;
+    } catch (final InvocationTargetException e) {
+      throw new RuntimeException("Exception while mapping", e.getTargetException());
+    } catch (final IllegalAccessException e) {
+      throw new RuntimeException("Exception while mapping", e);
+    }
+  }
+
+  private static final class Deallocator implements Runnable {
+    private final RandomAccessFile myRaf;
+    private final FileChannel myFc;
+    //This is the only place the actual native offset is kept for use by unsafe.freeMemory();
+    private final long actualNativeBaseOffset;
+    private final long myCapacity;
+    private final StepBoolean valid = new StepBoolean(true); //only place for this
+
+    Deallocator(final long nativeBaseOffset, final long capacityBytes,
+        final RandomAccessFile raf) {
+      myRaf = raf;
+      assert myRaf != null;
+      myFc = myRaf.getChannel();
+      actualNativeBaseOffset = nativeBaseOffset;
+      assert actualNativeBaseOffset != 0;
+      myCapacity = capacityBytes;
+      assert myCapacity != 0;
+    }
+
+    StepBoolean getValid() {
+      return valid;
+    }
+
+    @Override
+    public void run() throws IllegalStateException {
+      deallocate(true);
+    }
+
+    boolean deallocate(final boolean calledFromCleaner) throws IllegalStateException {
+      if (valid.change()) {
+        if (calledFromCleaner) {
+          // Warn about non-deterministic resource cleanup.
+          LOG.warning("A direct mapped resource was not closed explicitly");
+        }
+        unmap();
+        return true;
+      }
+      return false;
+    }
+
+    /**
+     * Removes existing mapping.  <i>unmap0</i> is a native method in FileChannelImpl.c. See
+     * reference at top of class.
+     */
+    private void unmap() throws IllegalStateException {
+      try {
+        FILE_CHANNEL_IMPL_UNMAP0_METHOD.invoke(myFc, actualNativeBaseOffset, myCapacity);
+        myRaf.close();
+      } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException | IOException e) {
+        throw new IllegalStateException(String.format("Encountered %s exception while freeing memory", e.getClass()));
+      }
+    }
+  } //End of class Deallocator
+
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
index 8fbce11..01605f4 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
@@ -32,85 +32,92 @@
  * @author Lee Rhodes
  */
 final class BBNonNativeWritableBufferImpl extends NonNativeWritableBufferImpl {
-  private static final int id = BUFFER | NONNATIVE | BYTEBUF;
-  private final Object unsafeObj;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
   private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until we are done with it.
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
+  private final Object unsafeObj;
+  private final long nativeBaseOffset; //raw off-heap address of allocation base if ByteBuffer direct, else 0
 
   BBNonNativeWritableBufferImpl(
       final Object unsafeObj,
       final long nativeBaseOffset,
-      final long regionOffset,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final ByteBuffer byteBuf,
-      final MemoryRequestServer memReqSvr) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+      final long cumOffsetBytes,
+      final MemoryRequestServer memReqSvr,
+      final ByteBuffer byteBuf) {
+    super(capacityBytes);
     this.unsafeObj = unsafeObj;
     this.nativeBaseOffset = nativeBaseOffset;
+    this.offsetBytes = offsetBytes; //in ResourceImpl
+    this.capacityBytes = capacityBytes; //in ResourceImpl
+    this.typeId = removeNnBuf(typeId) | BYTEBUF | BUFFER | NONNATIVE; //in ResourceImpl
+    this.cumOffsetBytes = cumOffsetBytes; //in ResourceImpl
+    this.memReqSvr = memReqSvr; //in ResourceImpl
     this.byteBuf = byteBuf;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread(); //in ResourceImpl
   }
 
   @Override
-  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableBufferImpl(
-          unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, byteBuf, memReqSvr)
-        : new BBNonNativeWritableBufferImpl(
-          unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, byteBuf, memReqSvr);
-  }
+  BaseWritableBufferImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | REGION | (readOnly ? READONLY : 0);
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
-        : new BBNonNativeWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new BBWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr, byteBuf);
+    }
   }
 
   @Override
   BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableMemoryImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
-        : new BBNonNativeWritableMemoryImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new BBWritableMemoryImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableMemoryImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    }
+  }
+
+  @Override
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | DUPLICATE | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new BBWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    }
   }
 
   @Override
   public ByteBuffer getByteBuffer() {
-    assertValid();
     return byteBuf;
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    assertValid();
-    return memReqSvr;
-  }
-
-  @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
-  }
-
-  @Override
   Object getUnsafeObject() {
-    assertValid();
     return unsafeObj;
   }
 
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java
index 60ed085..7d4d39d 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java
@@ -32,75 +32,77 @@
  * @author Lee Rhodes
  */
 final class BBNonNativeWritableMemoryImpl extends NonNativeWritableMemoryImpl {
-  private static final int id = MEMORY | NONNATIVE | BYTEBUF;
-  private final Object unsafeObj;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
   private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until we are done with it.
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
+  private final Object unsafeObj;
+  private final long nativeBaseOffset; //raw off-heap address of allocation base if ByteBuffer direct, else 0
 
   BBNonNativeWritableMemoryImpl(
       final Object unsafeObj,
       final long nativeBaseOffset,
-      final long regionOffset,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final ByteBuffer byteBuf,
-      final MemoryRequestServer memReqSvr) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+      final long cumOffsetBytes,
+      final MemoryRequestServer memReqSvr,
+      final ByteBuffer byteBuf) {
+    super();
     this.unsafeObj = unsafeObj;
     this.nativeBaseOffset = nativeBaseOffset;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | BYTEBUF | MEMORY | NONNATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
     this.byteBuf = byteBuf;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableMemoryImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, getByteBuffer(), memReqSvr)
-        : new BBNonNativeWritableMemoryImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, getByteBuffer(), memReqSvr);
+  BaseWritableMemoryImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | REGION | (readOnly ? READONLY : 0);
+
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new BBWritableMemoryImpl(
+          unsafeObj, nativeBaseOffset, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableMemoryImpl(
+          unsafeObj, nativeBaseOffset, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr, byteBuf);
+    }
   }
 
   @Override
   BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
-        : new BBNonNativeWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new BBWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    }
   }
 
   @Override
   public ByteBuffer getByteBuffer() {
-    assertValid();
     return byteBuf;
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    assertValid();
-    return memReqSvr;
-  }
-
-  @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
-  }
-
-  @Override
   Object getUnsafeObject() {
-    assertValid();
     return unsafeObj;
   }
 
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
index 0288488..b1b4b5c 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
@@ -32,85 +32,92 @@
  * @author Lee Rhodes
  */
 final class BBWritableBufferImpl extends NativeWritableBufferImpl {
-  private static final int id = BUFFER | NATIVE | BYTEBUF;
+  private final ByteBuffer byteBuf;    //holds a reference to a ByteBuffer until we are done with it.
   private final Object unsafeObj;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
-  private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until we are done with it.
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
+  private final long nativeBaseOffset; //raw off-heap address of allocation base if ByteBuffer direct, else 0
 
   BBWritableBufferImpl(
       final Object unsafeObj,
       final long nativeBaseOffset,
-      final long regionOffset,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final ByteBuffer byteBuf,
-      final MemoryRequestServer memReqSvr) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+      final long cumOffsetBytes,
+      final MemoryRequestServer memReqSvr,
+      final ByteBuffer byteBuf) {
+    super(capacityBytes);
     this.unsafeObj = unsafeObj;
     this.nativeBaseOffset = nativeBaseOffset;
+    this.offsetBytes = offsetBytes; //in ResourceImpl
+    this.capacityBytes = capacityBytes; //in ResourceImpl
+    this.typeId = removeNnBuf(typeId) | BYTEBUF | BUFFER | NATIVE; //in ResourceImpl
+    this.cumOffsetBytes = cumOffsetBytes; //in ResourceImpl
+    this.memReqSvr = memReqSvr; //in ResourceImpl
     this.byteBuf = byteBuf;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread(); //in ResourceImpl
   }
 
   @Override
-  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, byteBuf, memReqSvr)
-        : new BBNonNativeWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, byteBuf, memReqSvr);
-  }
+  BaseWritableBufferImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | REGION | (readOnly ? READONLY : 0);
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
-        : new BBNonNativeWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new BBWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr, byteBuf);
+    }
   }
 
   @Override
   BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableMemoryImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
-        : new BBNonNativeWritableMemoryImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new BBWritableMemoryImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableMemoryImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    }
+  }
+
+  @Override
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | DUPLICATE | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new BBWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    }
   }
 
   @Override
   public ByteBuffer getByteBuffer() {
-    assertValid();
     return byteBuf;
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    assertValid();
-    return memReqSvr;
-  }
-
-  @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
-  }
-
-  @Override
   Object getUnsafeObject() {
-    assertValid();
     return unsafeObj;
   }
 
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java
index ad06dc9..ed6b349 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java
@@ -32,75 +32,77 @@
  * @author Lee Rhodes
  */
 final class BBWritableMemoryImpl extends NativeWritableMemoryImpl {
-  private static final int id = MEMORY | NATIVE | BYTEBUF;
-  private final Object unsafeObj;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
   private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until we are done with it.
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
+  private final Object unsafeObj;
+  private final long nativeBaseOffset; //raw off-heap address of allocation base if ByteBuffer direct, else 0
 
   BBWritableMemoryImpl(
       final Object unsafeObj,
       final long nativeBaseOffset,
-      final long regionOffset,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final ByteBuffer byteBuf,
-      final MemoryRequestServer memReqSvr) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+      final long cumOffsetBytes,
+      final MemoryRequestServer memReqSvr,
+      final ByteBuffer byteBuf) {
+    super();
     this.unsafeObj = unsafeObj;
     this.nativeBaseOffset = nativeBaseOffset;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | BYTEBUF | MEMORY | NATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
     this.byteBuf = byteBuf;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableMemoryImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, getByteBuffer(), memReqSvr)
-        : new BBNonNativeWritableMemoryImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, getByteBuffer(), memReqSvr);
+  BaseWritableMemoryImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | REGION | (readOnly ? READONLY : 0);
+
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new BBWritableMemoryImpl(
+          unsafeObj, nativeBaseOffset, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableMemoryImpl(
+          unsafeObj, nativeBaseOffset, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr, byteBuf);
+    }
   }
 
   @Override
   BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
-        : new BBNonNativeWritableBufferImpl(
-            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new BBWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new BBNonNativeWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr, byteBuf);
+    }
   }
 
   @Override
   public ByteBuffer getByteBuffer() {
-    assertValid();
     return byteBuf;
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    assertValid();
-    return memReqSvr;
-  }
-
-  @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
-  }
-
-  @Override
   Object getUnsafeObject() {
-    assertValid();
     return unsafeObj;
   }
 
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseBufferImpl.java
index 7bc1340..74bfdab 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseBufferImpl.java
@@ -20,10 +20,10 @@
 package org.apache.datasketches.memory.internal;
 
 import org.apache.datasketches.memory.BaseBuffer;
-import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.BufferPositionInvariantsException;
 
 /**
- * A new positional API. This is different from and simpler than Java BufferImpl positional approach.
+ * A new positional API. This is different from and simpler than Java Buffer positional approach.
  * <ul><li>All based on longs instead of ints.</li>
  * <li>Eliminated "mark". Rarely used and confusing with its silent side effects.</li>
  * <li>The invariants are {@code 0 <= start <= position <= end <= capacity}.</li>
@@ -39,22 +39,21 @@
  *
  * @author Lee Rhodes
  */
-public abstract class BaseBufferImpl extends BaseStateImpl implements BaseBuffer {
+public abstract class BaseBufferImpl extends ResourceImpl implements BaseBuffer {
   private long capacity;
   private long start = 0;
   private long pos = 0;
   private long end;
 
-  //Pass-through ctor
-  BaseBufferImpl(final Object unsafeObj, final long nativeBaseOffset,
-      final long regionOffset, final long capacityBytes) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+  //Pass-through constructor
+  BaseBufferImpl(final long capacityBytes) {
+    super();
     capacity = end = capacityBytes;
   }
 
   @Override
   public final BaseBufferImpl incrementPosition(final long increment) {
-    incrementAndAssertPositionForRead(pos, increment);
+    incrementAndCheckPositionForRead(pos, increment);
     return this;
   }
 
@@ -97,31 +96,12 @@
 
   @Override
   public final BaseBufferImpl setPosition(final long position) {
-    assertInvariants(start, position, end, capacity);
-    pos = position;
-    return this;
+    return setStartPositionEnd(start, position, end);
   }
 
   @Override
-  public final BaseBufferImpl setAndCheckPosition(final long position) {
-    checkInvariants(start, position, end, capacity);
-    pos = position;
-    return this;
-  }
-
-  @Override
-  public final BaseBufferImpl setStartPositionEnd(final long start, final long position,
-      final long end) {
-    assertInvariants(start, position, end, capacity);
-    this.start = start;
-    this.end = end;
-    pos = position;
-    return this;
-  }
-
-  @Override
-  public final BaseBufferImpl setAndCheckStartPositionEnd(final long start, final long position,
-      final long end) {
+  public final BaseBufferImpl setStartPositionEnd(final long start, final long position, final long end) {
+    checkValid();
     checkInvariants(start, position, end, capacity);
     this.start = start;
     this.end = end;
@@ -130,24 +110,8 @@
   }
 
   //RESTRICTED
-  //Position checks are only used for Buffers
-  //asserts are used for primitives, not used at runtime
-  final void incrementAndAssertPositionForRead(final long position, final long increment) {
-    assertValid();
-    final long newPos = position + increment;
-    assertInvariants(start, newPos, end, capacity);
-    pos = newPos;
-  }
 
-  final void incrementAndAssertPositionForWrite(final long position, final long increment) {
-    assertValid();
-    assert !isReadOnly() : "BufferImpl is read-only.";
-    final long newPos = position + increment;
-    assertInvariants(start, newPos, end, capacity);
-    pos = newPos;
-  }
-
-  //checks are used for arrays and apply at runtime
+  //used for buffer arrays and apply at runtime
   final void incrementAndCheckPositionForRead(final long position, final long increment) {
     checkValid();
     final long newPos = position + increment;
@@ -155,54 +119,23 @@
     pos = newPos;
   }
 
+  //used for buffer arrays and apply at runtime
   final void incrementAndCheckPositionForWrite(final long position, final long increment) {
-    checkValidForWrite();
-    final long newPos = position + increment;
-    checkInvariants(start, newPos, end, capacity);
-    pos = newPos;
-  }
-
-  final void checkValidForWrite() {
-    checkValid();
-    if (isReadOnly()) {
-      throw new ReadOnlyException("BufferImpl is read-only.");
-    }
+    checkNotReadOnly();
+    incrementAndCheckPositionForRead(position, increment);
   }
 
   /**
    * The invariants equation is: {@code 0 <= start <= position <= end <= capacity}.
-   * If this equation is violated and assertions are enabled,
-   * an <i>AssertionError</i> will be thrown.
+   * If this equation is violated a <i>BufferPositionInvariantsException</i> will be thrown.
    * @param start the lowest start position
    * @param pos the current position
    * @param end the highest position
    * @param cap the capacity of the backing buffer.
    */
-  static final void assertInvariants(final long start, final long pos, final long end,
-      final long cap) {
-    assert (start | pos | end | cap | (pos - start) | (end - pos) | (cap - end) ) >= 0L
-        : "Violation of Invariants: "
-        + "start: " + start
-        + " <= pos: " + pos
-        + " <= end: " + end
-        + " <= cap: " + cap
-        + "; (pos - start): " + (pos - start)
-        + ", (end - pos): " + (end - pos)
-        + ", (cap - end): " + (cap - end);
-  }
-
-  /**
-   * The invariants equation is: {@code 0 <= start <= position <= end <= capacity}.
-   * If this equation is violated an <i>IllegalArgumentException</i> will be thrown.
-   * @param start the lowest start position
-   * @param pos the current position
-   * @param end the highest position
-   * @param cap the capacity of the backing buffer.
-   */
-  static final void checkInvariants(final long start, final long pos, final long end,
-        final long cap) {
+  static final void checkInvariants(final long start, final long pos, final long end, final long cap) {
     if ((start | pos | end | cap | (pos - start) | (end - pos) | (cap - end) ) < 0L) {
-      throw new IllegalArgumentException(
+      throw new BufferPositionInvariantsException(
           "Violation of Invariants: "
               + "start: " + start
               + " <= pos: " + pos
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java
deleted file mode 100644
index 42062c1..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-import static org.apache.datasketches.memory.internal.UnsafeUtil.LS;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.assertBounds;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.checkBounds;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.apache.datasketches.memory.BaseState;
-import org.apache.datasketches.memory.MemoryRequestServer;
-import org.apache.datasketches.memory.ReadOnlyException;
-
-/**
- * Keeps key configuration state for MemoryImpl and BufferImpl plus some common static variables
- * and check methods.
- *
- * @author Lee Rhodes
- */
-@SuppressWarnings("restriction")
-public abstract class BaseStateImpl implements BaseState {
-
-  //Monitoring
-  static final AtomicLong currentDirectMemoryAllocations_ = new AtomicLong();
-  static final AtomicLong currentDirectMemoryAllocated_ = new AtomicLong();
-  static final AtomicLong currentDirectMemoryMapAllocations_ = new AtomicLong();
-  static final AtomicLong currentDirectMemoryMapAllocated_ = new AtomicLong();
-
-  //class type IDs. Do not change the bit orders
-  //The first 3 bits are set dynamically
-  // 0000 0XXX
-  static final int READONLY = 1;
-  static final int REGION = 2;
-  static final int DUPLICATE = 4;
-
-  //The following 4 bits are set by the 16 leaf nodes
-  // 000X X000
-  static final int HEAP = 0;
-  static final int DIRECT = 1 << 3;
-  static final int MAP = 2 << 3;
-  static final int BYTEBUF = 3 << 3;
-
-  // 00X0 0000
-  static final int NATIVE = 0;
-  static final int NONNATIVE = 1 << 5;
-
-  // 0X00 0000
-  static final int MEMORY = 0;
-  static final int BUFFER = 1 << 6;
-
-  private final long capacityBytes_;
-
-  /**
-   * This becomes the base offset used by all Unsafe calls. It is cumulative in that in includes
-   * all offsets from regions, user-defined offsets when creating MemoryImpl, and the array object
-   * header offset when creating MemoryImpl from primitive arrays.
-   */
-  private final long cumBaseOffset_;
-
-  /**
-   *
-   * @param unsafeObj The primitive backing array. It may be null. Used by Unsafe calls.
-   * @param nativeBaseOffset The off-heap memory address including DirectByteBuffer split offsets.
-   * @param regionOffset This offset defines address zero of this object (usually a region)
-   * relative to address zero of the backing resource. It is used to compute cumBaseOffset.
-   * This will be loaded from heap ByteBuffers, which have a similar field used for slices.
-   * It is used by region() and writableRegion().
-   * This offset does not include the size of an object array header, if there is one.
-   * @param capacityBytes the capacity of this object. Used by all methods when checking bounds.
-   */
-  BaseStateImpl(final Object unsafeObj, final long nativeBaseOffset, final long regionOffset,
-      final long capacityBytes) {
-    capacityBytes_ = capacityBytes;
-    cumBaseOffset_ = regionOffset + (unsafeObj == null
-        ? nativeBaseOffset
-        : UnsafeUtil.getArrayBaseOffset(unsafeObj.getClass()));
-  }
-
-  //Byte Order Related
-
-  @Override
-  public final ByteOrder getTypeByteOrder() {
-    return isNonNativeType() ? Util.NON_NATIVE_BYTE_ORDER : ByteOrder.nativeOrder();
-  }
-
-  /**
-   * Returns true if the given byteOrder is the same as the native byte order.
-   * @param byteOrder the given byte order
-   * @return true if the given byteOrder is the same as the native byte order.
-   */
-  public static boolean isNativeByteOrder(final ByteOrder byteOrder) {
-    if (byteOrder == null) {
-      throw new IllegalArgumentException("ByteOrder parameter cannot be null.");
-    }
-    return ByteOrder.nativeOrder() == byteOrder;
-  }
-
-  @Override
-  public final boolean isByteOrderCompatible(final ByteOrder byteOrder) {
-    final ByteOrder typeBO = getTypeByteOrder();
-    return typeBO == ByteOrder.nativeOrder() && typeBO == byteOrder;
-  }
-
-  @Override
-  public final boolean equals(final Object that) {
-    if (this == that) { return true; }
-    return that instanceof BaseStateImpl
-      ? CompareAndCopy.equals(this, (BaseStateImpl) that)
-      : false;
-  }
-
-  @Override
-  public final boolean equalTo(final long thisOffsetBytes, final Object that,
-      final long thatOffsetBytes, final long lengthBytes) {
-    return that instanceof BaseStateImpl
-      ? CompareAndCopy.equals(this, thisOffsetBytes, (BaseStateImpl) that, thatOffsetBytes, lengthBytes)
-      : false;
-  }
-
-  //Overridden by ByteBuffer Leafs
-  @Override
-  public ByteBuffer getByteBuffer() {
-    return null;
-  }
-
-  @Override
-  public final long getCapacity() {
-    assertValid();
-    return capacityBytes_;
-  }
-
-  @Override
-  public final long getCumulativeOffset() {
-    assertValid();
-    return cumBaseOffset_;
-  }
-
-  @Override
-  public final long getCumulativeOffset(final long offsetBytes) {
-    assertValid();
-    return cumBaseOffset_ + offsetBytes;
-  }
-
-  //Documented in WritableMemory and WritableBuffer interfaces.
-  //Implemented in the Leaf nodes; Required here by toHex(...).
-  abstract MemoryRequestServer getMemoryRequestServer();
-
-  //Overridden by ByteBuffer, Direct and Map leafs
-  long getNativeBaseOffset() {
-    return 0;
-  }
-
-  @Override
-  public final long getRegionOffset() {
-    final Object unsafeObj = getUnsafeObject();
-    return unsafeObj == null
-        ? cumBaseOffset_ - getNativeBaseOffset()
-        : cumBaseOffset_ - UnsafeUtil.getArrayBaseOffset(unsafeObj.getClass());
-  }
-
-  @Override
-  public final long getRegionOffset(final long offsetBytes) {
-    return getRegionOffset() + offsetBytes;
-  }
-
-  //Overridden by all leafs
-  abstract int getTypeId();
-
-  //Overridden by Heap and ByteBuffer Leafs. Made public as getArray() in WritableMemoryImpl and
-  // WritableBufferImpl
-  Object getUnsafeObject() {
-    return null;
-  }
-
-  @Override
-  public final boolean hasArray() {
-    assertValid();
-    return getUnsafeObject() != null;
-  }
-
-  @Override
-  public final int hashCode() {
-    return (int) xxHash64(0, capacityBytes_, 0); //xxHash64() calls checkValid()
-  }
-
-  @Override
-  public final long xxHash64(final long offsetBytes, final long lengthBytes, final long seed) {
-    checkValid();
-    return XxHash64.hash(getUnsafeObject(), cumBaseOffset_ + offsetBytes, lengthBytes, seed);
-  }
-
-  @Override
-  public final long xxHash64(final long in, final long seed) {
-    return XxHash64.hash(in, seed);
-  }
-
-  @Override
-  public final boolean hasByteBuffer() {
-    assertValid();
-    return getByteBuffer() != null;
-  }
-
-  @Override
-  public final boolean isDirect() {
-    return getUnsafeObject() == null;
-  }
-
-  @Override
-  public final boolean isReadOnly() {
-    assertValid();
-    return isReadOnlyType();
-  }
-
-  @Override
-  public final boolean isSameResource(final Object that) {
-    checkValid();
-    if (that == null) { return false; }
-    final BaseStateImpl that1 = (BaseStateImpl) that;
-    that1.checkValid();
-    if (this == that1) { return true; }
-
-    return cumBaseOffset_ == that1.cumBaseOffset_
-            && capacityBytes_ == that1.capacityBytes_
-            && getUnsafeObject() == that1.getUnsafeObject()
-            && getByteBuffer() == that1.getByteBuffer();
-  }
-
-  //Overridden by Direct and Map leafs
-  @Override
-  public boolean isValid() {
-    return true;
-  }
-
-  //ASSERTS AND CHECKS
-  final void assertValid() {
-    assert isValid() : "MemoryImpl not valid.";
-  }
-
-  void checkValid() {
-    if (!isValid()) {
-      throw new IllegalStateException("MemoryImpl not valid.");
-    }
-  }
-
-  final void assertValidAndBoundsForRead(final long offsetBytes, final long lengthBytes) {
-    assertValid();
-    // capacityBytes_ is intentionally read directly instead of calling getCapacity()
-    // because the later can make JVM to not inline the assert code path (and entirely remove it)
-    // even though it does nothing in production code path.
-    assertBounds(offsetBytes, lengthBytes, capacityBytes_);
-  }
-
-  final void assertValidAndBoundsForWrite(final long offsetBytes, final long lengthBytes) {
-    assertValid();
-    // capacityBytes_ is intentionally read directly instead of calling getCapacity()
-    // because the later can make JVM to not inline the assert code path (and entirely remove it)
-    // even though it does nothing in production code path.
-    assertBounds(offsetBytes, lengthBytes, capacityBytes_);
-    assert !isReadOnly() : "MemoryImpl is read-only.";
-  }
-
-  @Override
-  public final void checkValidAndBounds(final long offsetBytes, final long lengthBytes) {
-    checkValid();
-    //read capacityBytes_ directly to eliminate extra checkValid() call
-    checkBounds(offsetBytes, lengthBytes, capacityBytes_);
-  }
-
-  final void checkValidAndBoundsForWrite(final long offsetBytes, final long lengthBytes) {
-    checkValid();
-    //read capacityBytes_ directly to eliminate extra checkValid() call
-    checkBounds(offsetBytes, lengthBytes, capacityBytes_);
-    if (isReadOnly()) {
-      throw new ReadOnlyException("MemoryImpl is read-only.");
-    }
-  }
-
-  //TYPE ID Management
-  final boolean isReadOnlyType() {
-    return (getTypeId() & READONLY) > 0;
-  }
-
-  final static byte setReadOnlyType(final byte type, final boolean readOnly) {
-    return (byte)((type & ~1) | (readOnly ? READONLY : 0));
-  }
-
-  final boolean isRegionType() {
-    return (getTypeId() & REGION) > 0;
-  }
-
-  final boolean isDuplicateType() {
-    return (getTypeId() & DUPLICATE) > 0;
-  }
-
-  //The following are set by the leaf nodes
-  final boolean isBufferType() {
-    return (getTypeId() & BUFFER) > 0;
-  }
-
-  final boolean isNonNativeType() {
-    return (getTypeId() & NONNATIVE) > 0;
-  }
-
-  final boolean isHeapType() {
-    return (getTypeId() >>> 3 & 3) == 0;
-  }
-
-  final boolean isDirectType() {
-    return (getTypeId() >>> 3 & 3) == 1;
-  }
-
-  final boolean isMapType() {
-    return (getTypeId() >>> 3 & 3) == 2;
-  }
-
-  final boolean isBBType() {
-    return (getTypeId() >>> 3 & 3) == 3;
-  }
-
-  //TO STRING
-  /**
-   * Decodes the resource type. This is primarily for debugging.
-   * @param typeId the given typeId
-   * @return a human readable string.
-   */
-  public static final String typeDecode(final int typeId) {
-    final StringBuilder sb = new StringBuilder();
-    final int group1 = typeId & 0x7;
-    switch (group1) {
-      case 1 : sb.append("ReadOnly, "); break;
-      case 2 : sb.append("Region, "); break;
-      case 3 : sb.append("ReadOnly Region, "); break;
-      case 4 : sb.append("Duplicate, "); break;
-      case 5 : sb.append("ReadOnly Duplicate, "); break;
-      case 6 : sb.append("Region Duplicate, "); break;
-      case 7 : sb.append("ReadOnly Region Duplicate, "); break;
-      default: break;
-    }
-    final int group2 = (typeId >>> 3) & 0x3;
-    switch (group2) {
-      case 0 : sb.append("Heap, "); break;
-      case 1 : sb.append("Direct, "); break;
-      case 2 : sb.append("Map, "); break;
-      case 3 : sb.append("ByteBuffer, "); break;
-      default: break;
-    }
-    final int group3 = (typeId >>> 5) & 0x1;
-    switch (group3) {
-      case 0 : sb.append("Native, "); break;
-      case 1 : sb.append("NonNative, "); break;
-      default: break;
-    }
-    final int group4 = (typeId >>> 6) & 0x1;
-    switch (group4) {
-      case 0 : sb.append("Memory"); break;
-      case 1 : sb.append("Buffer"); break;
-      default: break;
-    }
-    return sb.toString();
-  }
-
-  @Override
-  public final String toHexString(final String header, final long offsetBytes,
-      final int lengthBytes) {
-    checkValid();
-    final String klass = this.getClass().getSimpleName();
-    final String s1 = String.format("(..., %d, %d)", offsetBytes, lengthBytes);
-    final long hcode = hashCode() & 0XFFFFFFFFL;
-    final String call = ".toHexString" + s1 + ", hashCode: " + hcode;
-    final StringBuilder sb = new StringBuilder();
-    sb.append("### ").append(klass).append(" SUMMARY ###").append(LS);
-    sb.append("Header Comment      : ").append(header).append(LS);
-    sb.append("Call Parameters     : ").append(call);
-    return toHex(this, sb.toString(), offsetBytes, lengthBytes);
-  }
-
-  /**
-   * Returns a formatted hex string of an area of this object.
-   * Used primarily for testing.
-   * @param state the BaseStateImpl
-   * @param preamble a descriptive header
-   * @param offsetBytes offset bytes relative to the MemoryImpl start
-   * @param lengthBytes number of bytes to convert to a hex string
-   * @return a formatted hex string in a human readable array
-   */
-  static final String toHex(final BaseStateImpl state, final String preamble, final long offsetBytes,
-      final int lengthBytes) {
-    final long capacity = state.getCapacity();
-    UnsafeUtil.checkBounds(offsetBytes, lengthBytes, capacity);
-    final StringBuilder sb = new StringBuilder();
-    final Object uObj = state.getUnsafeObject();
-    final String uObjStr;
-    final long uObjHeader;
-    if (uObj == null) {
-      uObjStr = "null";
-      uObjHeader = 0;
-    } else {
-      uObjStr =  uObj.getClass().getSimpleName() + ", " + (uObj.hashCode() & 0XFFFFFFFFL);
-      uObjHeader = UnsafeUtil.getArrayBaseOffset(uObj.getClass());
-    }
-    final ByteBuffer bb = state.getByteBuffer();
-    final String bbStr = bb == null ? "null"
-            : bb.getClass().getSimpleName() + ", " + (bb.hashCode() & 0XFFFFFFFFL);
-    final MemoryRequestServer memReqSvr = state.getMemoryRequestServer();
-    final String memReqStr = memReqSvr != null
-        ? memReqSvr.getClass().getSimpleName() + ", " + (memReqSvr.hashCode() & 0XFFFFFFFFL)
-        : "null";
-    final long cumBaseOffset = state.getCumulativeOffset();
-    sb.append(preamble).append(LS);
-    sb.append("UnsafeObj, hashCode : ").append(uObjStr).append(LS);
-    sb.append("UnsafeObjHeader     : ").append(uObjHeader).append(LS);
-    sb.append("ByteBuf, hashCode   : ").append(bbStr).append(LS);
-    sb.append("RegionOffset        : ").append(state.getRegionOffset()).append(LS);
-    sb.append("Capacity            : ").append(capacity).append(LS);
-    sb.append("CumBaseOffset       : ").append(cumBaseOffset).append(LS);
-    sb.append("MemReq, hashCode    : ").append(memReqStr).append(LS);
-    sb.append("Valid               : ").append(state.isValid()).append(LS);
-    sb.append("Read Only           : ").append(state.isReadOnly()).append(LS);
-    sb.append("Type Byte Order     : ").append(state.getTypeByteOrder().toString()).append(LS);
-    sb.append("Native Byte Order   : ").append(ByteOrder.nativeOrder().toString()).append(LS);
-    sb.append("JDK Runtime Version : ").append(UnsafeUtil.JDK).append(LS);
-    //Data detail
-    sb.append("Data, littleEndian  :  0  1  2  3  4  5  6  7");
-
-    for (long i = 0; i < lengthBytes; i++) {
-      final int b = unsafe.getByte(uObj, cumBaseOffset + offsetBytes + i) & 0XFF;
-      if (i % 8 == 0) { //row header
-        sb.append(String.format("%n%20s: ", offsetBytes + i));
-      }
-      sb.append(String.format("%02x ", b));
-    }
-    sb.append(LS);
-
-    return sb.toString();
-  }
-
-  //MONITORING
-
-  /**
-   * Gets the current number of active direct memory allocations.
-   * @return the current number of active direct memory allocations.
-   */
-  public static final long getCurrentDirectMemoryAllocations() {
-    return BaseStateImpl.currentDirectMemoryAllocations_.get();
-  }
-
-  /**
-   * Gets the current size of active direct memory allocated.
-   * @return the current size of active direct memory allocated.
-   */
-  public static final long getCurrentDirectMemoryAllocated() {
-    return BaseStateImpl.currentDirectMemoryAllocated_.get();
-  }
-
-  /**
-   * Gets the current number of active direct memory map allocations.
-   * @return the current number of active direct memory map allocations.
-   */
-  public static final long getCurrentDirectMemoryMapAllocations() {
-    return BaseStateImpl.currentDirectMemoryMapAllocations_.get();
-  }
-
-  /**
-   * Gets the current size of active direct memory map allocated.
-   * @return the current size of active direct memory map allocated.
-   */
-  public static final long getCurrentDirectMemoryMapAllocated() {
-    return BaseStateImpl.currentDirectMemoryMapAllocated_.get();
-  }
-
-  //REACHABILITY FENCE
-  static void reachabilityFence(final Object obj) { }
-
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
index e1dbe93..61b3725 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
@@ -27,7 +27,6 @@
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_INT_INDEX_SCALE;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_LONG_INDEX_SCALE;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_SHORT_INDEX_SCALE;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.checkBounds;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
 
 import java.nio.ByteBuffer;
@@ -41,19 +40,6 @@
 import org.apache.datasketches.memory.WritableBuffer;
 import org.apache.datasketches.memory.WritableMemory;
 
-/*
- * Developer notes: The heavier methods, such as put/get arrays, duplicate, region, clear, fill,
- * compareTo, etc., use hard checks (check*() and incrementAndCheck*() methods), which execute at
- * runtime and throw exceptions if violated. The cost of the runtime checks are minor compared to
- * the rest of the work these methods are doing.
- *
- * <p>The light weight methods, such as put/get primitives, use asserts (assert*() and
- * incrementAndAssert*() methods), which only execute when asserts are enabled and JIT will remove
- * them entirely from production runtime code. The offset versions of the light weight methods will
- * simplify to a single unsafe call, which is further simplified by JIT to an intrinsic that is
- * often a single CPU instruction.
- */
-
 /**
  * Common base of native-ordered and non-native-ordered {@link WritableBuffer} implementations.
  * Contains methods which are agnostic to the byte order.
@@ -61,11 +47,8 @@
 @SuppressWarnings("restriction")
 public abstract class BaseWritableBufferImpl extends BaseBufferImpl implements WritableBuffer {
 
-  //Pass-through ctor
-  BaseWritableBufferImpl(final Object unsafeObj, final long nativeBaseOffset,
-      final long regionOffset, final long capacityBytes) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
-  }
+  //Pass-through constructor
+  BaseWritableBufferImpl(final long capacityBytes) { super(capacityBytes); }
 
   /**
    * The static constructor that chooses the correct ByteBuffer leaf node based on the byte order.
@@ -75,16 +58,17 @@
    * @param memReqSvr the requested MemoryRequestServer, which may be null.
    * @return this class constructed via the leaf node.
    */
-  public static BaseWritableBufferImpl wrapByteBuffer(
+  public static WritableBuffer wrapByteBuffer(
       final ByteBuffer byteBuf, final boolean localReadOnly, final ByteOrder byteOrder,
       final MemoryRequestServer memReqSvr) {
     final AccessByteBuffer abb = new AccessByteBuffer(byteBuf);
     final int typeId = (abb.resourceReadOnly || localReadOnly) ? READONLY : 0;
+    final long cumOffsetBytes = abb.initialCumOffset;
     final BaseWritableBufferImpl bwbi = Util.isNativeByteOrder(byteOrder)
         ? new BBWritableBufferImpl(abb.unsafeObj, abb.nativeBaseOffset,
-            abb.regionOffset, abb.capacityBytes, typeId, byteBuf, memReqSvr)
+            abb.offsetBytes, abb.capacityBytes, typeId, cumOffsetBytes, memReqSvr, byteBuf)
         : new BBNonNativeWritableBufferImpl(abb.unsafeObj, abb.nativeBaseOffset,
-            abb.regionOffset, abb.capacityBytes,  typeId, byteBuf, memReqSvr);
+            abb.offsetBytes, abb.capacityBytes,  typeId, cumOffsetBytes, memReqSvr, byteBuf);
     bwbi.setStartPositionEnd(0, byteBuf.position(), byteBuf.limit());
     return bwbi;
   }
@@ -92,25 +76,25 @@
   //REGIONS
   @Override
   public Buffer region() {
-    return writableRegionImpl(getPosition(), getEnd() - getPosition(), true, getTypeByteOrder());
+    return writableRegionImpl(getPosition(), getEnd() - getPosition(), true, getByteOrder());
   }
 
   @Override
   public Buffer region(final long offsetBytes, final long capacityBytes, final ByteOrder byteOrder) {
     final WritableBuffer buf = writableRegionImpl(offsetBytes, capacityBytes, true, byteOrder);
-    buf.setAndCheckStartPositionEnd(0, 0, capacityBytes);
+    buf.setStartPositionEnd(0, 0, capacityBytes);
     return buf;
   }
 
   @Override
   public WritableBuffer writableRegion() {
-    return writableRegionImpl(getPosition(), getEnd() - getPosition(), false, getTypeByteOrder());
+    return writableRegionImpl(getPosition(), getEnd() - getPosition(), false, getByteOrder());
   }
 
   @Override
   public WritableBuffer writableRegion(final long offsetBytes, final long capacityBytes, final ByteOrder byteOrder) {
     final WritableBuffer wbuf = writableRegionImpl(offsetBytes, capacityBytes, false, byteOrder);
-    wbuf.setAndCheckStartPositionEnd(0, 0, capacityBytes);
+    wbuf.setStartPositionEnd(0, 0, capacityBytes);
     return wbuf;
   }
 
@@ -126,13 +110,13 @@
     return wbuf;
   }
 
-  abstract BaseWritableBufferImpl toWritableRegion(
+  abstract WritableBuffer toWritableRegion(
       long offsetBytes, long capcityBytes, boolean readOnly, ByteOrder byteOrder);
 
   //DUPLICATES
   @Override
   public Buffer duplicate() {
-    return writableDuplicateImpl(true, getTypeByteOrder());
+    return writableDuplicateImpl(true, getByteOrder());
   }
 
   @Override
@@ -142,7 +126,7 @@
 
   @Override
   public WritableBuffer writableDuplicate() {
-    return writableDuplicateImpl(false, getTypeByteOrder());
+    return writableDuplicateImpl(false, getByteOrder());
   }
 
   @Override
@@ -154,8 +138,8 @@
     if (isReadOnly() && !localReadOnly) {
       throw new ReadOnlyException("Writable duplicate of a read-only Buffer is not allowed.");
     }
-    final boolean readOnly = isReadOnly() || localReadOnly;
-    final WritableBuffer wbuf = toDuplicate(readOnly, byteOrder);
+    final boolean finalReadOnly = isReadOnly() || localReadOnly;
+    final WritableBuffer wbuf = toDuplicate(finalReadOnly, byteOrder);
     wbuf.setStartPositionEnd(getStart(), getPosition(), getEnd());
     return wbuf;
   }
@@ -179,24 +163,24 @@
       throw new ReadOnlyException(
           "Converting a read-only Buffer to a writable Memory is not allowed.");
     }
-    final boolean readOnly = isReadOnly() || localReadOnly;
-    final WritableMemory wmem = toWritableMemory(readOnly, byteOrder);
+    final boolean finalReadOnly = isReadOnly() || localReadOnly;
+    final WritableMemory wmem = toWritableMemory(finalReadOnly, byteOrder);
     return wmem;
   }
 
-  abstract BaseWritableMemoryImpl toWritableMemory(boolean readOnly, ByteOrder byteOrder);
+  abstract WritableMemory toWritableMemory(boolean readOnly, ByteOrder byteOrder);
 
   //PRIMITIVE getX() and getXArray()
   @Override
   public final boolean getBoolean() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_BOOLEAN_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_BOOLEAN_INDEX_SCALE);
     return unsafe.getBoolean(getUnsafeObject(), getCumulativeOffset(pos));
   }
 
   @Override
   public final boolean getBoolean(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
     return unsafe.getBoolean(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -206,7 +190,7 @@
     final long pos = getPosition();
     final long copyBytes = lengthBooleans;
     incrementAndCheckPositionForRead(pos, copyBytes);
-    checkBounds(dstOffsetBooleans, lengthBooleans, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetBooleans, lengthBooleans, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             getUnsafeObject(),
             getCumulativeOffset(pos),
@@ -218,13 +202,13 @@
   @Override
   public final byte getByte() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_BYTE_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_BYTE_INDEX_SCALE);
     return unsafe.getByte(getUnsafeObject(), getCumulativeOffset(pos));
   }
 
   @Override
   public final byte getByte(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
     return unsafe.getByte(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -234,7 +218,7 @@
     final long pos = getPosition();
     final long copyBytes = lengthBytes;
     incrementAndCheckPositionForRead(pos, copyBytes);
-    checkBounds(dstOffsetBytes, lengthBytes, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetBytes, lengthBytes, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             getUnsafeObject(),
             getCumulativeOffset(pos),
@@ -246,45 +230,45 @@
   //PRIMITIVE getX() Native Endian (used by both endians)
   final char getNativeOrderedChar() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_CHAR_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_CHAR_INDEX_SCALE);
     return unsafe.getChar(getUnsafeObject(), getCumulativeOffset(pos));
   }
 
   final char getNativeOrderedChar(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
     return unsafe.getChar(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
   final int getNativeOrderedInt() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_INT_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_INT_INDEX_SCALE);
     return unsafe.getInt(getUnsafeObject(), getCumulativeOffset(pos));
   }
 
   final int getNativeOrderedInt(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_INT_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_INT_INDEX_SCALE);
     return unsafe.getInt(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
   final long getNativeOrderedLong() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_LONG_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_LONG_INDEX_SCALE);
     return unsafe.getLong(getUnsafeObject(), getCumulativeOffset(pos));
   }
 
   final long getNativeOrderedLong(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_LONG_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_LONG_INDEX_SCALE);
     return unsafe.getLong(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
   final short getNativeOrderedShort() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_SHORT_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_SHORT_INDEX_SCALE);
     return unsafe.getShort(getUnsafeObject(), getCumulativeOffset(pos));
   }
 
   final short getNativeOrderedShort(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
     return unsafe.getShort(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -292,12 +276,12 @@
   @Override
   public final int compareTo(final long thisOffsetBytes, final long thisLengthBytes,
       final Buffer thatBuf, final long thatOffsetBytes, final long thatLengthBytes) {
-    return CompareAndCopy.compare((BaseStateImpl)this, thisOffsetBytes, thisLengthBytes,
-        (BaseStateImpl)thatBuf, thatOffsetBytes, thatLengthBytes);
+    return CompareAndCopy.compare((ResourceImpl)this, thisOffsetBytes, thisLengthBytes,
+        (ResourceImpl)thatBuf, thatOffsetBytes, thatLengthBytes);
   }
 
   /*
-   * Develper notes: There is no copyTo for Buffers because of the ambiguity of what to do with
+   * Developer notes: There is no copyTo for Buffers because of the ambiguity of what to do with
    * the positional values. Switch to MemoryImpl view to do copyTo.
    */
 
@@ -305,13 +289,13 @@
   @Override
   public final void putBoolean(final boolean value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_BOOLEAN_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_BOOLEAN_INDEX_SCALE);
     unsafe.putBoolean(getUnsafeObject(), getCumulativeOffset(pos), value);
   }
 
   @Override
   public final void putBoolean(final long offsetBytes, final boolean value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
     unsafe.putBoolean(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
@@ -321,7 +305,7 @@
     final long pos = getPosition();
     final long copyBytes = lengthBooleans;
     incrementAndCheckPositionForWrite(pos, copyBytes);
-    checkBounds(srcOffsetBooleans, lengthBooleans, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetBooleans, lengthBooleans, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             srcArray,
             ARRAY_BOOLEAN_BASE_OFFSET + srcOffsetBooleans,
@@ -333,13 +317,13 @@
   @Override
   public final void putByte(final byte value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_BYTE_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_BYTE_INDEX_SCALE);
     unsafe.putByte(getUnsafeObject(), getCumulativeOffset(pos), value);
   }
 
   @Override
   public final void putByte(final long offsetBytes, final byte value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
     unsafe.putByte(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
@@ -349,7 +333,7 @@
     final long pos = getPosition();
     final long copyBytes = lengthBytes;
     incrementAndCheckPositionForWrite(pos, copyBytes);
-    checkBounds(srcOffsetBytes, lengthBytes, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetBytes, lengthBytes, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             srcArray,
             ARRAY_BYTE_BASE_OFFSET + srcOffsetBytes,
@@ -361,52 +345,56 @@
   //PRIMITIVE putX() Native Endian (used by both endians)
   final void putNativeOrderedChar(final char value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_CHAR_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_CHAR_INDEX_SCALE);
     unsafe.putChar(getUnsafeObject(), getCumulativeOffset(pos), value);
   }
 
   final void putNativeOrderedChar(final long offsetBytes, final char value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
     unsafe.putChar(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
   final void putNativeOrderedInt(final int value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_INT_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_INT_INDEX_SCALE);
     unsafe.putInt(getUnsafeObject(), getCumulativeOffset(pos), value);
   }
 
   final void putNativeOrderedInt(final long offsetBytes, final int value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_INT_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_INT_INDEX_SCALE);
     unsafe.putInt(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
   final void putNativeOrderedLong(final long value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_LONG_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_LONG_INDEX_SCALE);
     unsafe.putLong(getUnsafeObject(), getCumulativeOffset(pos), value);
   }
 
   final void putNativeOrderedLong(final long offsetBytes, final long value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
     unsafe.putLong(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
   final void putNativeOrderedShort(final short value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_SHORT_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_SHORT_INDEX_SCALE);
     unsafe.putShort(getUnsafeObject(), getCumulativeOffset(pos), value);
   }
 
   final void putNativeOrderedShort(final long offsetBytes, final short value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
     unsafe.putShort(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
-  //OTHER
-  @Override
-  public final Object getArray() {
-    assertValid();
+  //OTHER WRITE METHODS
+
+  /**
+   * Returns the primitive backing array, otherwise null.
+   * @return the primitive backing array, otherwise null.
+   */
+  final Object getArray() {
+    checkValid();
     return getUnsafeObject();
   }
 
@@ -417,7 +405,7 @@
 
   @Override
   public final void fill(final byte value) {
-    checkValidForWrite();
+    checkNotReadOnly();
     long pos = getPosition();
     long len = getEnd() - pos;
     checkInvariants(getStart(), pos + len, getEnd(), getCapacity());
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java
index 1e75d7d..a65f889 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java
@@ -27,7 +27,6 @@
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_INT_INDEX_SCALE;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_LONG_INDEX_SCALE;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_SHORT_INDEX_SCALE;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.checkBounds;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
 import static org.apache.datasketches.memory.internal.Util.negativeCheck;
 
@@ -44,28 +43,14 @@
 import org.apache.datasketches.memory.ReadOnlyException;
 import org.apache.datasketches.memory.Utf8CodingException;
 import org.apache.datasketches.memory.WritableBuffer;
-import org.apache.datasketches.memory.WritableHandle;
-import org.apache.datasketches.memory.WritableMapHandle;
 import org.apache.datasketches.memory.WritableMemory;
 
-/*
- * Developer notes: The heavier methods, such as put/get arrays, duplicate, region, clear, fill,
- * compareTo, etc., use hard checks (checkValid*() and checkBounds()), which execute at runtime and
- * throw exceptions if violated. The cost of the runtime checks are minor compared to the rest of
- * the work these methods are doing.
- *
- * <p>The light weight methods, such as put/get primitives, use asserts (assertValid*()), which only
- * execute when asserts are enabled and JIT will remove them entirely from production runtime code.
- * The light weight methods will simplify to a single unsafe call, which is further simplified by
- * JIT to an intrinsic that is often a single CPU instruction.
- */
-
 /**
  * Common base of native-ordered and non-native-ordered {@link WritableMemory} implementations.
  * Contains methods which are agnostic to the byte order.
  */
 @SuppressWarnings("restriction")
-public abstract class BaseWritableMemoryImpl extends BaseStateImpl implements WritableMemory {
+public abstract class BaseWritableMemoryImpl extends ResourceImpl implements WritableMemory {
 
   //1KB of empty bytes for speedy clear()
   private final static byte[] EMPTY_BYTES;
@@ -74,11 +59,8 @@
     EMPTY_BYTES = new byte[1024];
   }
 
-  //Pass-through ctor
-  BaseWritableMemoryImpl(final Object unsafeObj, final long nativeBaseOffset,
-      final long regionOffset, final long capacityBytes) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
-  }
+  //Pass-through constructor
+  BaseWritableMemoryImpl() { }
 
   /**
    * The static constructor that chooses the correct Heap leaf node based on the byte order.
@@ -90,12 +72,13 @@
    * @param memReqSvr the requested MemoryRequestServer, which may be null.
    * @return this class constructed via the leaf node.
    */
-  public static BaseWritableMemoryImpl wrapHeapArray(final Object arr, final long offsetBytes, final long lengthBytes,
+  public static WritableMemory wrapHeapArray(final Object arr, final long offsetBytes, final long lengthBytes,
       final boolean localReadOnly, final ByteOrder byteOrder, final MemoryRequestServer memReqSvr) {
-    final int typeId = localReadOnly ? READONLY : 0;
+    final long cumOffsetBytes = UnsafeUtil.getArrayBaseOffset(arr.getClass()) + offsetBytes;
+    final int typeId = (localReadOnly ? READONLY : 0);
     return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableMemoryImpl(arr, offsetBytes, lengthBytes, typeId, memReqSvr)
-        : new HeapNonNativeWritableMemoryImpl(arr, offsetBytes, lengthBytes, typeId, memReqSvr);
+        ? new HeapWritableMemoryImpl(arr, offsetBytes, lengthBytes, typeId, cumOffsetBytes, memReqSvr)
+        : new HeapNonNativeWritableMemoryImpl(arr, offsetBytes, lengthBytes, typeId, cumOffsetBytes, memReqSvr);
   }
 
   /**
@@ -106,16 +89,19 @@
    * @param memReqSvr the requested MemoryRequestServer, which may be null.
    * @return this class constructed via the leaf node.
    */
-  public static BaseWritableMemoryImpl wrapByteBuffer(
+  public static WritableMemory wrapByteBuffer(
       final ByteBuffer byteBuf, final boolean localReadOnly, final ByteOrder byteOrder,
       final MemoryRequestServer memReqSvr) {
     final AccessByteBuffer abb = new AccessByteBuffer(byteBuf);
     final int typeId = (abb.resourceReadOnly || localReadOnly) ? READONLY : 0;
+    final long cumOffsetBytes = abb.offsetBytes + (abb.unsafeObj == null
+        ? abb.nativeBaseOffset
+        : UnsafeUtil.getArrayBaseOffset(abb.unsafeObj.getClass()));
     return Util.isNativeByteOrder(byteOrder)
         ? new BBWritableMemoryImpl(abb.unsafeObj, abb.nativeBaseOffset,
-            abb.regionOffset, abb.capacityBytes, typeId, byteBuf, memReqSvr)
+            abb.offsetBytes, abb.capacityBytes, typeId, cumOffsetBytes, memReqSvr, byteBuf)
         : new BBNonNativeWritableMemoryImpl(abb.unsafeObj, abb.nativeBaseOffset,
-            abb.regionOffset, abb.capacityBytes,  typeId, byteBuf, memReqSvr);
+            abb.offsetBytes, abb.capacityBytes,  typeId, cumOffsetBytes, memReqSvr, byteBuf);
   }
 
   /**
@@ -127,17 +113,26 @@
    * @param byteOrder the requested byte-order
    * @return this class constructed via the leaf node.
    */
-  public static WritableMapHandle wrapMap(final File file, final long fileOffsetBytes,
+  public static WritableMemory wrapMap(final File file, final long fileOffsetBytes,
       final long capacityBytes, final boolean localReadOnly, final ByteOrder byteOrder) {
     final AllocateDirectWritableMap dirWMap =
         new AllocateDirectWritableMap(file, fileOffsetBytes, capacityBytes, localReadOnly);
     final int typeId = (dirWMap.resourceReadOnly || localReadOnly) ? READONLY : 0;
+    final long cumOffsetBytes = dirWMap.nativeBaseOffset;
     final BaseWritableMemoryImpl wmem = Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableMemoryImpl(dirWMap.nativeBaseOffset, 0L, capacityBytes,
-            typeId, dirWMap.getValid())
-        : new MapNonNativeWritableMemoryImpl(dirWMap.nativeBaseOffset, 0L, capacityBytes,
-            typeId, dirWMap.getValid());
-    return new WritableMapHandleImpl(dirWMap, wmem);
+        ? new MapWritableMemoryImpl(
+            dirWMap,
+            0L,
+            capacityBytes,
+            typeId,
+            cumOffsetBytes)
+        : new MapNonNativeWritableMemoryImpl(
+            dirWMap,
+            0L,
+            capacityBytes,
+            typeId,
+            cumOffsetBytes);
+    return wmem;
   }
 
   /**
@@ -147,46 +142,57 @@
    * @param memReqSvr the requested MemoryRequestServer, which may be null
    * @return this class constructed via the leaf node.
    */
-  public static WritableHandle wrapDirect(final long capacityBytes,
+  public static WritableMemory wrapDirect(final long capacityBytes,
       final ByteOrder byteOrder, final MemoryRequestServer memReqSvr) {
     final AllocateDirect direct = new AllocateDirect(capacityBytes);
     final int typeId = 0; //direct is never read-only on construction
+    final long nativeBaseOffset = direct.getNativeBaseOffset();
+    final long cumOffsetBytes = nativeBaseOffset;
     final BaseWritableMemoryImpl wmem = Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableMemoryImpl(direct.getNativeBaseOffset(), 0L, capacityBytes,
-            typeId, direct.getValid(), memReqSvr)
-        : new DirectNonNativeWritableMemoryImpl(direct.getNativeBaseOffset(), 0L, capacityBytes,
-            typeId, direct.getValid(), memReqSvr);
-
-    final WritableHandle handle = new WritableDirectHandleImpl(direct, wmem);
-    return handle;
+        ? new DirectWritableMemoryImpl(
+            direct,
+            0L,
+            capacityBytes,
+            typeId,
+            cumOffsetBytes,
+            memReqSvr)
+        : new DirectNonNativeWritableMemoryImpl(
+            direct,
+            0L,
+            capacityBytes,
+            typeId,
+            cumOffsetBytes,
+            memReqSvr);
+    return wmem;
   }
 
   //REGIONS
   @Override
-  public Memory region(final long offsetBytes, final long capacityBytes, final ByteOrder byteOrder) {
-    return writableRegionImpl(offsetBytes, capacityBytes, true, byteOrder);
+  public Memory region(final long regionOffsetBytes, final long capacityBytes, final ByteOrder byteOrder) {
+    return writableRegionImpl(regionOffsetBytes, capacityBytes, true, byteOrder);
   }
 
   @Override
-  public WritableMemory writableRegion(final long offsetBytes, final long capacityBytes, final ByteOrder byteOrder) {
-    return writableRegionImpl(offsetBytes, capacityBytes, false, byteOrder);
+  public WritableMemory writableRegion(final long regionOffsetBytes, final long capacityBytes,
+      final ByteOrder byteOrder) {
+    return writableRegionImpl(regionOffsetBytes, capacityBytes, false, byteOrder);
   }
 
-  WritableMemory writableRegionImpl(final long offsetBytes, final long capacityBytes,
+  private WritableMemory writableRegionImpl(final long regionOffsetBytes, final long capacityBytes,
       final boolean localReadOnly, final ByteOrder byteOrder) {
     if (isReadOnly() && !localReadOnly) {
       throw new ReadOnlyException("Writable region of a read-only Memory is not allowed.");
     }
-    negativeCheck(offsetBytes, "offsetBytes must be >= 0");
+    negativeCheck(regionOffsetBytes, "offsetBytes must be >= 0");
     negativeCheck(capacityBytes, "capacityBytes must be >= 0");
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
-    checkValidAndBounds(offsetBytes, capacityBytes);
-    final boolean readOnly = isReadOnly() || localReadOnly;
-    return toWritableRegion(offsetBytes, capacityBytes, readOnly, byteOrder);
+    checkValidAndBounds(regionOffsetBytes, capacityBytes);
+    final boolean finalReadOnly = isReadOnly() || localReadOnly;
+    return toWritableRegion(regionOffsetBytes, capacityBytes, finalReadOnly, byteOrder);
   }
 
-  abstract BaseWritableMemoryImpl toWritableRegion(
-      long offsetBytes, long capcityBytes, boolean readOnly, ByteOrder byteOrder);
+  abstract WritableMemory toWritableRegion(
+      long regionOffsetBytes, long capacityBytes, boolean finalReadOnly, ByteOrder byteOrder);
 
   //AS BUFFER
   @Override
@@ -199,24 +205,24 @@
     return asWritableBuffer(false, byteOrder);
   }
 
-  WritableBuffer asWritableBuffer(final boolean localReadOnly, final ByteOrder byteOrder) {
+  private WritableBuffer asWritableBuffer(final boolean localReadOnly, final ByteOrder byteOrder) {
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
     if (isReadOnly() && !localReadOnly) {
       throw new ReadOnlyException(
           "Converting a read-only Memory to a writable Buffer is not allowed.");
     }
-    final boolean readOnly = isReadOnly() || localReadOnly;
-    final WritableBuffer wbuf = toWritableBuffer(readOnly, byteOrder);
+    final boolean finalReadOnly = isReadOnly() || localReadOnly;
+    final WritableBuffer wbuf = toWritableBuffer(finalReadOnly, byteOrder);
     wbuf.setStartPositionEnd(0, 0, getCapacity());
     return wbuf;
   }
 
-  abstract BaseWritableBufferImpl toWritableBuffer(boolean readOnly, ByteOrder byteOrder);
+  abstract WritableBuffer toWritableBuffer(boolean finalReadOnly, ByteOrder byteOrder);
 
   //PRIMITIVE getX() and getXArray()
   @Override
   public final boolean getBoolean(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
     return unsafe.getBoolean(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -225,7 +231,7 @@
       final int dstOffsetBooleans, final int lengthBooleans) {
     final long copyBytes = lengthBooleans;
     checkValidAndBounds(offsetBytes, copyBytes);
-    checkBounds(dstOffsetBooleans, lengthBooleans, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetBooleans, lengthBooleans, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         getUnsafeObject(),
         getCumulativeOffset(offsetBytes),
@@ -236,7 +242,7 @@
 
   @Override
   public final byte getByte(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
     return unsafe.getByte(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -245,7 +251,7 @@
       final int dstOffsetBytes, final int lengthBytes) {
     final long copyBytes = lengthBytes;
     checkValidAndBounds(offsetBytes, copyBytes);
-    checkBounds(dstOffsetBytes, lengthBytes, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetBytes, lengthBytes, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         getUnsafeObject(),
         getCumulativeOffset(offsetBytes),
@@ -258,7 +264,7 @@
   public final int getCharsFromUtf8(final long offsetBytes, final int utf8LengthBytes,
       final Appendable dst) throws IOException, Utf8CodingException {
     checkValidAndBounds(offsetBytes, utf8LengthBytes);
-    return Utf8.getCharsFromUtf8(offsetBytes, utf8LengthBytes, dst, getCumulativeOffset(),
+    return Utf8.getCharsFromUtf8(offsetBytes, utf8LengthBytes, dst, getCumulativeOffset(0),
         getUnsafeObject());
   }
 
@@ -276,22 +282,22 @@
 
   //PRIMITIVE getX() Native Endian (used by both endians)
   final char getNativeOrderedChar(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
     return unsafe.getChar(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
   final int getNativeOrderedInt(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_INT_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_INT_INDEX_SCALE);
     return unsafe.getInt(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
   final long getNativeOrderedLong(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_LONG_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_LONG_INDEX_SCALE);
     return unsafe.getLong(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
   final short getNativeOrderedShort(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
     return unsafe.getShort(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -299,14 +305,14 @@
   @Override
   public final int compareTo(final long thisOffsetBytes, final long thisLengthBytes,
       final Memory thatMem, final long thatOffsetBytes, final long thatLengthBytes) {
-    return CompareAndCopy.compare((BaseStateImpl)this, thisOffsetBytes, thisLengthBytes,
-        (BaseStateImpl)thatMem, thatOffsetBytes, thatLengthBytes);
+    return CompareAndCopy.compare((ResourceImpl)this, thisOffsetBytes, thisLengthBytes,
+        (ResourceImpl)thatMem, thatOffsetBytes, thatLengthBytes);
   }
 
   @Override
   public final void copyTo(final long srcOffsetBytes, final WritableMemory destination,
       final long dstOffsetBytes, final long lengthBytes) {
-    CompareAndCopy.copy((BaseStateImpl)this, srcOffsetBytes, (BaseStateImpl)destination,
+    CompareAndCopy.copy((ResourceImpl)this, srcOffsetBytes, (ResourceImpl)destination,
         dstOffsetBytes, lengthBytes);
   }
 
@@ -328,7 +334,7 @@
   //PRIMITIVE putX() and putXArray() implementations
   @Override
   public final void putBoolean(final long offsetBytes, final boolean value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
     unsafe.putBoolean(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
@@ -337,7 +343,7 @@
       final int srcOffsetBooleans, final int lengthBooleans) {
     final long copyBytes = lengthBooleans;
     checkValidAndBoundsForWrite(offsetBytes, copyBytes);
-    checkBounds(srcOffsetBooleans, lengthBooleans, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetBooleans, lengthBooleans, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         srcArray,
         ARRAY_BOOLEAN_BASE_OFFSET + srcOffsetBooleans,
@@ -349,7 +355,7 @@
 
   @Override
   public final void putByte(final long offsetBytes, final byte value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
     unsafe.putByte(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
@@ -358,7 +364,7 @@
       final int srcOffsetBytes, final int lengthBytes) {
     final long copyBytes = lengthBytes;
     checkValidAndBoundsForWrite(offsetBytes, copyBytes);
-    checkBounds(srcOffsetBytes, lengthBytes, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetBytes, lengthBytes, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         srcArray,
         ARRAY_BYTE_BASE_OFFSET + srcOffsetBytes,
@@ -371,35 +377,39 @@
   @Override
   public final long putCharsToUtf8(final long offsetBytes, final CharSequence src) {
     checkValid();
-    return Utf8.putCharsToUtf8(offsetBytes, src, getCapacity(), getCumulativeOffset(),
+    return Utf8.putCharsToUtf8(offsetBytes, src, getCapacity(), getCumulativeOffset(0),
         getUnsafeObject());
   }
 
   //PRIMITIVE putX() Native Endian (used by both endians)
   final void putNativeOrderedChar(final long offsetBytes, final char value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
     unsafe.putChar(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
   final void putNativeOrderedInt(final long offsetBytes, final int value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_INT_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_INT_INDEX_SCALE);
     unsafe.putInt(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
   final void putNativeOrderedLong(final long offsetBytes, final long value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
     unsafe.putLong(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
   final void putNativeOrderedShort(final long offsetBytes, final short value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
     unsafe.putShort(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
   //OTHER WRITE METHODS
-  @Override
-  public final Object getArray() {
-    assertValid();
+
+  /**
+   * Returns the primitive backing array, otherwise null.
+   * @return the primitive backing array, otherwise null.
+   */
+  final Object getArray() {
+    checkValid();
     return getUnsafeObject();
   }
 
@@ -421,7 +431,7 @@
 
   @Override
   public final void clearBits(final long offsetBytes, final byte bitMask) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
     final long cumBaseOff = getCumulativeOffset(offsetBytes);
     int value = unsafe.getByte(getUnsafeObject(), cumBaseOff) & 0XFF;
     value &= ~bitMask;
@@ -446,7 +456,7 @@
 
   @Override
   public final void setBits(final long offsetBytes, final byte bitMask) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
     final long myOffset = getCumulativeOffset(offsetBytes);
     final byte value = unsafe.getByte(getUnsafeObject(), myOffset);
     unsafe.putByte(getUnsafeObject(), myOffset, (byte)(value | bitMask));
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/CompareAndCopy.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/CompareAndCopy.java
index cb5b9b0..052b84e 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/CompareAndCopy.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/CompareAndCopy.java
@@ -25,7 +25,6 @@
 import static org.apache.datasketches.memory.internal.UnsafeUtil.INT_SHIFT;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.LONG_SHIFT;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.SHORT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.checkBounds;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
 import static org.apache.datasketches.memory.internal.Util.UNSAFE_COPY_THRESHOLD_BYTES;
 
@@ -38,12 +37,12 @@
   private CompareAndCopy() { }
 
   static int compare(
-      final BaseStateImpl state1, final long offsetBytes1, final long lengthBytes1,
-      final BaseStateImpl state2, final long offsetBytes2, final long lengthBytes2) {
+      final ResourceImpl state1, final long offsetBytes1, final long lengthBytes1,
+      final ResourceImpl state2, final long offsetBytes2, final long lengthBytes2) {
     state1.checkValid();
-    checkBounds(offsetBytes1, lengthBytes1, state1.getCapacity());
+    ResourceImpl.checkBounds(offsetBytes1, lengthBytes1, state1.getCapacity());
     state2.checkValid();
-    checkBounds(offsetBytes2, lengthBytes2, state2.getCapacity());
+    ResourceImpl.checkBounds(offsetBytes2, lengthBytes2, state2.getCapacity());
     final long cumOff1 = state1.getCumulativeOffset(offsetBytes1);
     final long cumOff2 = state2.getCumulativeOffset(offsetBytes2);
     final Object arr1 = state1.getUnsafeObject();
@@ -60,22 +59,22 @@
     return Long.compare(lengthBytes1, lengthBytes2);
   }
 
-  static boolean equals(final BaseStateImpl state1, final BaseStateImpl state2) {
+  static boolean equals(final ResourceImpl state1, final ResourceImpl state2) {
     final long cap1 = state1.getCapacity();
     final long cap2 = state2.getCapacity();
     return (cap1 == cap2) && equals(state1, 0, state2, 0, cap1);
   }
 
-  //Developer notes: this is subtlely different from (campare == 0) in that this has an early
+  //Developer notes: this is subtlety different from (compare == 0) in that this has an early
   // stop if the arrays and offsets are the same as there is only one length.  Also this can take
   // advantage of chunking with longs, while compare cannot.
   static boolean equals(
-      final BaseStateImpl state1, final long offsetBytes1,
-      final BaseStateImpl state2, final long offsetBytes2, long lengthBytes) {
+      final ResourceImpl state1, final long offsetBytes1,
+      final ResourceImpl state2, final long offsetBytes2, long lengthBytes) {
     state1.checkValid();
-    checkBounds(offsetBytes1, lengthBytes, state1.getCapacity());
+    ResourceImpl.checkBounds(offsetBytes1, lengthBytes, state1.getCapacity());
     state2.checkValid();
-    checkBounds(offsetBytes2, lengthBytes, state2.getCapacity());
+    ResourceImpl.checkBounds(offsetBytes2, lengthBytes, state2.getCapacity());
     long cumOff1 = state1.getCumulativeOffset(offsetBytes1);
     long cumOff2 = state2.getCumulativeOffset(offsetBytes2);
     final Object arr1 = state1.getUnsafeObject(); //could be null
@@ -112,12 +111,12 @@
     return true;
   }
 
-  static void copy(final BaseStateImpl srcState, final long srcOffsetBytes,
-      final BaseStateImpl dstState, final long dstOffsetBytes, final long lengthBytes) {
+  static void copy(final ResourceImpl srcState, final long srcOffsetBytes,
+      final ResourceImpl dstState, final long dstOffsetBytes, final long lengthBytes) {
     srcState.checkValid();
-    checkBounds(srcOffsetBytes, lengthBytes, srcState.getCapacity());
+    ResourceImpl.checkBounds(srcOffsetBytes, lengthBytes, srcState.getCapacity());
     dstState.checkValid();
-    checkBounds(dstOffsetBytes, lengthBytes, dstState.getCapacity());
+    ResourceImpl.checkBounds(dstOffsetBytes, lengthBytes, dstState.getCapacity());
     final long srcAdd = srcState.getCumulativeOffset(srcOffsetBytes);
     final long dstAdd = dstState.getCumulativeOffset(dstOffsetBytes);
     copyMemory(srcState.getUnsafeObject(), srcAdd, dstState.getUnsafeObject(), dstAdd,
@@ -201,7 +200,7 @@
   static void getNonNativeChars(final Object unsafeObj, long cumOffsetBytes,
       long copyBytes, final char[] dstArray, int dstOffsetChars,
       int lengthChars) {
-    checkBounds(dstOffsetChars, lengthChars, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetChars, lengthChars, dstArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkChars = (int) (chunkBytes >> CHAR_SHIFT);
@@ -228,7 +227,7 @@
   static void getNonNativeDoubles(final Object unsafeObj, long cumOffsetBytes,
       long copyBytes, final double[] dstArray, int dstOffsetDoubles,
       int lengthDoubles) {
-    checkBounds(dstOffsetDoubles, lengthDoubles, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetDoubles, lengthDoubles, dstArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkDoubles = (int) (chunkBytes >> DOUBLE_SHIFT);
@@ -257,7 +256,7 @@
   static void getNonNativeFloats(final Object unsafeObj, long cumOffsetBytes,
       long copyBytes, final float[] dstArray, int dstOffsetFloats,
       int lengthFloats) {
-    checkBounds(dstOffsetFloats, lengthFloats, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetFloats, lengthFloats, dstArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkFloats = (int) (chunkBytes >> FLOAT_SHIFT);
@@ -284,7 +283,7 @@
   static void getNonNativeInts(final Object unsafeObj, long cumOffsetBytes,
       long copyBytes, final int[] dstArray, int dstOffsetInts,
       int lengthInts) {
-    checkBounds(dstOffsetInts, lengthInts, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetInts, lengthInts, dstArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkInts = (int) (chunkBytes >> INT_SHIFT);
@@ -311,7 +310,7 @@
   static void getNonNativeLongs(final Object unsafeObj, long cumOffsetBytes,
       long copyBytes, final long[] dstArray, int dstOffsetLongs,
       int lengthLongs) {
-    checkBounds(dstOffsetLongs, lengthLongs, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetLongs, lengthLongs, dstArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkLongs = (int) (chunkBytes >> LONG_SHIFT);
@@ -338,7 +337,7 @@
   static void getNonNativeShorts(final Object unsafeObj, long cumOffsetBytes,
       long copyBytes, final short[] dstArray, int dstOffsetShorts,
       int lengthShorts) {
-    checkBounds(dstOffsetShorts, lengthShorts, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetShorts, lengthShorts, dstArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkShorts = (int) (chunkBytes >> SHORT_SHIFT);
@@ -364,7 +363,7 @@
 
   static void putNonNativeChars(final char[] srcArray, int srcOffsetChars, int lengthChars,
       long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
-    checkBounds(srcOffsetChars, lengthChars, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetChars, lengthChars, srcArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkChars = (int) (chunkBytes >> CHAR_SHIFT);
@@ -390,7 +389,7 @@
 
   static void putNonNativeDoubles(final double[] srcArray, int srcOffsetDoubles,
       int lengthDoubles, long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
-    checkBounds(srcOffsetDoubles, lengthDoubles, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetDoubles, lengthDoubles, srcArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkDoubles = (int) (chunkBytes >> DOUBLE_SHIFT);
@@ -418,7 +417,7 @@
 
   static void putNonNativeFloats(final float[] srcArray, int srcOffsetFloats,
       int lengthFloats, long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
-    checkBounds(srcOffsetFloats, lengthFloats, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetFloats, lengthFloats, srcArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkFloats = (int) (chunkBytes >> FLOAT_SHIFT);
@@ -444,7 +443,7 @@
 
   static void putNonNativeInts(final int[] srcArray, int srcOffsetInts, int lengthInts,
       long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
-    checkBounds(srcOffsetInts, lengthInts, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetInts, lengthInts, srcArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkInts = (int) (chunkBytes >> INT_SHIFT);
@@ -470,7 +469,7 @@
 
   static void putNonNativeLongs(final long[] srcArray, int srcOffsetLongs, int lengthLongs,
       long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
-    checkBounds(srcOffsetLongs, lengthLongs, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetLongs, lengthLongs, srcArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkLongs = (int) (chunkBytes >> LONG_SHIFT);
@@ -496,7 +495,7 @@
 
   static void putNonNativeShorts(final short[] srcArray, int srcOffsetShorts,
       int lengthShorts, long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
-    checkBounds(srcOffsetShorts, lengthShorts, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetShorts, lengthShorts, srcArray.length);
     while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
       final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
       final int chunkShorts = (int) (chunkBytes >> SHORT_SHIFT);
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableBufferImpl.java
index 3b0a183..5a1dd68 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableBufferImpl.java
@@ -31,76 +31,94 @@
  * @author Lee Rhodes
  */
 final class DirectNonNativeWritableBufferImpl extends NonNativeWritableBufferImpl {
-  private static final int id = BUFFER | NONNATIVE | DIRECT;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
-  private final StepBoolean valid; //a reference only
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
+  private final AllocateDirect direct;
 
   DirectNonNativeWritableBufferImpl(
-      final long nativeBaseOffset,
-      final long regionOffset,
+      final AllocateDirect direct,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final StepBoolean valid,
+      final long cumOffsetBytes,
       final MemoryRequestServer memReqSvr) {
-    super(null, nativeBaseOffset, regionOffset, capacityBytes);
-    this.nativeBaseOffset = nativeBaseOffset;
-    this.valid = valid;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    super(capacityBytes);
+    this.direct = direct;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | DIRECT | BUFFER | NONNATIVE; //initially cannot be ReadOnly
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid, memReqSvr)
-        : new DirectNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid, memReqSvr);
-  }
+  BaseWritableBufferImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | REGION | (readOnly ? READONLY : 0);
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr)
-        : new DirectNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr);
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableBufferImpl(
+          direct, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableBufferImpl(
+          direct, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
   BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr)
-        : new DirectNonNativeWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableMemoryImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableMemoryImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    assertValid();
-    return memReqSvr;
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | DUPLICATE | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableBufferImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableBufferImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
+  public void close() {
+    checkValid();
+    checkThread(owner);
+    direct.close();
   }
 
   @Override
-  int getTypeId() {
-    return typeId & 0xff;
+  Object getUnsafeObject() {
+    return null;
   }
 
   @Override
   public boolean isValid() {
-    return valid.get();
+    return direct.getValid().get();
   }
 
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableMemoryImpl.java
index 7be7e74..f9b9d3f 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableMemoryImpl.java
@@ -31,66 +31,79 @@
  * @author Lee Rhodes
  */
 final class DirectNonNativeWritableMemoryImpl extends NonNativeWritableMemoryImpl {
-  private static final int id = MEMORY | NONNATIVE | DIRECT;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
-  private final StepBoolean valid; //a reference only
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
+  private final AllocateDirect direct;
 
   DirectNonNativeWritableMemoryImpl(
-      final long nativeBaseOffset,
-      final long regionOffset,
+      final AllocateDirect direct,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final StepBoolean valid,
+      final long cumOffsetBytes,
       final MemoryRequestServer memReqSvr) {
-    super(null, nativeBaseOffset, regionOffset, capacityBytes);
-    this.nativeBaseOffset = nativeBaseOffset;
-    this.valid = valid;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    super();
+    this.direct = direct;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | DIRECT | MEMORY | NONNATIVE; //initially cannot be ReadOnly
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid, memReqSvr)
-        : new DirectNonNativeWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid, memReqSvr);
+  BaseWritableMemoryImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | REGION | (readOnly ? READONLY : 0);
+
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableMemoryImpl(
+          direct, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableMemoryImpl(
+          direct, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
   BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr)
-        : new DirectNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableBufferImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableBufferImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    assertValid();
-    return memReqSvr;
+  public void close() {
+    checkValid();
+    checkThread(owner);
+    direct.close();
   }
 
   @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+  Object getUnsafeObject() {
+    return null;
   }
 
   @Override
   public boolean isValid() {
-    return valid.get();
+    return direct.getValid().get();
   }
 
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectWritableBufferImpl.java
index 84e7d5e..02911b2 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectWritableBufferImpl.java
@@ -31,76 +31,94 @@
  * @author Lee Rhodes
  */
 final class DirectWritableBufferImpl extends NativeWritableBufferImpl {
-  private static final int id = BUFFER | NATIVE | DIRECT;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
-  private final StepBoolean valid; //a reference only
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
+  private final AllocateDirect direct;
 
   DirectWritableBufferImpl(
-      final long nativeBaseOffset,
-      final long regionOffset,
+      final AllocateDirect direct,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final StepBoolean valid,
+      final long cumOffsetBytes,
       final MemoryRequestServer memReqSvr) {
-    super(null, nativeBaseOffset, regionOffset, capacityBytes);
-    this.nativeBaseOffset = nativeBaseOffset;
-    this.valid = valid;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    super(capacityBytes);
+    this.direct = direct;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | DIRECT | BUFFER | NATIVE; //initially cannot be ReadOnly
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid, memReqSvr)
-        : new DirectNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid, memReqSvr);
-  }
+  BaseWritableBufferImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | REGION | (readOnly ? READONLY : 0);
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr)
-        : new DirectNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr);
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableBufferImpl(
+          direct, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableBufferImpl(
+          direct, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
   BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr)
-        : new DirectNonNativeWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableMemoryImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableMemoryImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    assertValid();
-    return memReqSvr;
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | DUPLICATE | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableBufferImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableBufferImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
+  public void close() {
+    checkValid();
+    checkThread(owner);
+    direct.close();
   }
 
   @Override
-  int getTypeId() {
-    return typeId & 0xff;
+  Object getUnsafeObject() {
+    return null;
   }
 
   @Override
   public boolean isValid() {
-    return valid.get();
+    return direct.getValid().get();
   }
 
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectWritableMemoryImpl.java
index 68a3461..2c1c1b1 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/DirectWritableMemoryImpl.java
@@ -31,66 +31,79 @@
  * @author Lee Rhodes
  */
 final class DirectWritableMemoryImpl extends NativeWritableMemoryImpl {
-  private static final int id = MEMORY | NATIVE | DIRECT;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
-  private final StepBoolean valid; //a reference only
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
+  private final AllocateDirect direct;
 
   DirectWritableMemoryImpl(
-      final long nativeBaseOffset,
-      final long regionOffset,
+      final AllocateDirect direct,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final StepBoolean valid,
+      final long cumOffsetBytes,
       final MemoryRequestServer memReqSvr) {
-    super(null, nativeBaseOffset, regionOffset, capacityBytes);
-    this.nativeBaseOffset = nativeBaseOffset;
-    this.valid = valid;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    super();
+    this.direct = direct;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | DIRECT | MEMORY | NATIVE; //initially cannot be ReadOnly
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid, memReqSvr)
-        : new DirectNonNativeWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid, memReqSvr);
+  BaseWritableMemoryImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | REGION | (readOnly ? READONLY : 0);
+
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableMemoryImpl(
+          direct, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableMemoryImpl(
+          direct, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
   BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr)
-        : new DirectNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new DirectWritableBufferImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new DirectNonNativeWritableBufferImpl(
+          direct, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    assertValid();
-    return memReqSvr;
+  public void close() {
+    checkValid();
+    checkThread(owner);
+    direct.close();
   }
 
   @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+  Object getUnsafeObject() {
+    return null;
   }
 
   @Override
   public boolean isValid() {
-    return valid.get();
+    return direct.getValid().get();
   }
 
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableBufferImpl.java
index 1a324f7..c78ecdc 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableBufferImpl.java
@@ -31,62 +31,77 @@
  * @author Lee Rhodes
  */
 final class HeapNonNativeWritableBufferImpl extends NonNativeWritableBufferImpl {
-  private static final int id = BUFFER | NONNATIVE | HEAP;
   private final Object unsafeObj;
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
 
   HeapNonNativeWritableBufferImpl(
       final Object unsafeObj,
-      final long regionOffset,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
+      final long cumOffsetBytes,
       final MemoryRequestServer memReqSvr) {
-    super(unsafeObj, 0L, regionOffset, capacityBytes);
+    super(capacityBytes);
     this.unsafeObj = unsafeObj;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | HEAP | BUFFER | NONNATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableBufferImpl(
-            unsafeObj, getRegionOffset(offsetBytes), capacityBytes, type, memReqSvr)
-        : new HeapNonNativeWritableBufferImpl(
-            unsafeObj, getRegionOffset(offsetBytes), capacityBytes, type, memReqSvr);
-  }
+  BaseWritableBufferImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | REGION | (readOnly ? READONLY : 0);
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableBufferImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr)
-        : new HeapNonNativeWritableBufferImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr);
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableBufferImpl(
+          unsafeObj, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableBufferImpl(
+          unsafeObj, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
   BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableMemoryImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr)
-        : new HeapNonNativeWritableMemoryImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableMemoryImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableMemoryImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    return memReqSvr;
-  }
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | DUPLICATE | (readOnly ? READONLY : 0);
 
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableBufferImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableBufferImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableMemoryImpl.java
index 91702c5..3c4e07b 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableMemoryImpl.java
@@ -31,52 +31,62 @@
  * @author Lee Rhodes
  */
 final class HeapNonNativeWritableMemoryImpl extends NonNativeWritableMemoryImpl {
-  private static final int id = MEMORY | NONNATIVE | HEAP;
   private final Object unsafeObj;
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
 
   HeapNonNativeWritableMemoryImpl(
       final Object unsafeObj,
-      final long regionOffset,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
+      final long cumOffsetBytes,
       final MemoryRequestServer memReqSvr) {
-    super(unsafeObj, 0L, regionOffset, capacityBytes);
+    super();
     this.unsafeObj = unsafeObj;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | HEAP | MEMORY | NONNATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableMemoryImpl(
-            unsafeObj, getRegionOffset(offsetBytes), capacityBytes, type, memReqSvr)
-        : new HeapNonNativeWritableMemoryImpl(
-            unsafeObj, getRegionOffset(offsetBytes), capacityBytes, type, memReqSvr);
+  BaseWritableMemoryImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | REGION | (readOnly ? READONLY : 0);
+
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableMemoryImpl(
+          unsafeObj, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableMemoryImpl(
+          unsafeObj, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
   BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableBufferImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr)
-        : new HeapNonNativeWritableBufferImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr);
-  }
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | (readOnly ? READONLY : 0);
 
-  @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    return memReqSvr;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableBufferImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableBufferImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapWritableBufferImpl.java
index 033ad87..782ef75 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapWritableBufferImpl.java
@@ -31,62 +31,77 @@
  * @author Lee Rhodes
  */
 final class HeapWritableBufferImpl extends NativeWritableBufferImpl {
-  private static final int id = BUFFER | NATIVE | HEAP;
   private final Object unsafeObj;
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
 
   HeapWritableBufferImpl(
       final Object unsafeObj,
-      final long regionOffset,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
+      final long cumOffsetBytes,
       final MemoryRequestServer memReqSvr) {
-    super(unsafeObj, 0L, regionOffset, capacityBytes);
+    super(capacityBytes);
     this.unsafeObj = unsafeObj;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | HEAP | BUFFER | NATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableBufferImpl(
-            unsafeObj, getRegionOffset(offsetBytes), capacityBytes, type, memReqSvr)
-        : new HeapNonNativeWritableBufferImpl(
-            unsafeObj, getRegionOffset(offsetBytes), capacityBytes, type, memReqSvr);
-  }
+  BaseWritableBufferImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | REGION | (readOnly ? READONLY : 0);
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableBufferImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr)
-        : new HeapNonNativeWritableBufferImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr);
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableBufferImpl(
+          unsafeObj, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableBufferImpl(
+          unsafeObj, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
   BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableMemoryImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr)
-        : new HeapNonNativeWritableMemoryImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr);
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableMemoryImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableMemoryImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    return memReqSvr;
-  }
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | DUPLICATE | (readOnly ? READONLY : 0);
 
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableBufferImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableBufferImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapWritableMemoryImpl.java
index d2f05d9..f3b8f87 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/HeapWritableMemoryImpl.java
@@ -31,52 +31,62 @@
  * @author Lee Rhodes
  */
 final class HeapWritableMemoryImpl extends NativeWritableMemoryImpl {
-  private static final int id = MEMORY | NATIVE | HEAP;
   private final Object unsafeObj;
-  private final MemoryRequestServer memReqSvr;
-  private final byte typeId;
 
   HeapWritableMemoryImpl(
       final Object unsafeObj,
-      final long regionOffset,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
+      final long cumOffsetBytes,
       final MemoryRequestServer memReqSvr) {
-    super(unsafeObj, 0L, regionOffset, capacityBytes);
+    super();
     this.unsafeObj = unsafeObj;
-    this.memReqSvr = memReqSvr;
-    this.typeId = (byte) (id | (typeId & 0x7));
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | HEAP | MEMORY | NATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    this.memReqSvr = memReqSvr; //in ResourceImpl
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableMemoryImpl(
-            unsafeObj, getRegionOffset(offsetBytes), capacityBytes, type, memReqSvr)
-        : new HeapNonNativeWritableMemoryImpl(
-            unsafeObj, getRegionOffset(offsetBytes), capacityBytes, type, memReqSvr);
+  BaseWritableMemoryImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | REGION | (readOnly ? READONLY : 0);
+
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableMemoryImpl(
+          unsafeObj, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableMemoryImpl(
+          unsafeObj, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
   BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableBufferImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr)
-        : new HeapNonNativeWritableBufferImpl(
-            unsafeObj, getRegionOffset(), getCapacity(), type, memReqSvr);
-  }
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | (readOnly ? READONLY : 0);
 
-  @Override
-  public MemoryRequestServer getMemoryRequestServer() {
-    return memReqSvr;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new HeapWritableBufferImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new HeapNonNativeWritableBufferImpl(
+          unsafeObj, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes, memReqSvr);
+    }
   }
 
   @Override
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapHandleImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapHandleImpl.java
deleted file mode 100644
index 6351478..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapHandleImpl.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-import org.apache.datasketches.memory.MapHandle;
-import org.apache.datasketches.memory.Memory;
-
-class MapHandleImpl implements MapHandle {
-
-  final AllocateDirectMap dirMap;
-  BaseWritableMemoryImpl wMem;
-
-  MapHandleImpl(final AllocateDirectMap dirMap, final BaseWritableMemoryImpl wMem) {
-    this.dirMap = dirMap;
-    this.wMem = wMem;
-  }
-
-  @Override
-  public Memory get() {
-    return wMem;
-  }
-
-  @Override
-  public void close() {
-    if (dirMap.doClose("MapHandle")) {
-      wMem = null;
-    }
-  }
-
-  @Override
-  public void load() {
-    dirMap.load();
-  }
-
-  @Override
-  public boolean isLoaded() {
-    return dirMap.isLoaded();
-  }
-
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableBufferImpl.java
index 31a4f1f..4871c3f 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableBufferImpl.java
@@ -21,7 +21,6 @@
 
 import java.nio.ByteOrder;
 
-import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableBuffer;
 
 /**
@@ -31,72 +30,114 @@
  * @author Lee Rhodes
  */
 final class MapNonNativeWritableBufferImpl extends NonNativeWritableBufferImpl {
-  private static final int id = BUFFER | NONNATIVE | MAP;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
-  private final StepBoolean valid; //a reference only
-  private final byte typeId;
+  private final AllocateDirectWritableMap dirWMap;
 
   MapNonNativeWritableBufferImpl(
-      final long nativeBaseOffset,
-      final long regionOffset,
+      final AllocateDirectWritableMap dirWMap,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final StepBoolean valid) {
-    super(null, nativeBaseOffset, regionOffset, capacityBytes);
-    this.nativeBaseOffset = nativeBaseOffset;
-    this.valid = valid;
-    this.typeId = (byte) (id | (typeId & 0x7));
+      final long cumOffsetBytes) {
+    super(capacityBytes);
+    this.dirWMap = dirWMap;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | MAP | BUFFER | NONNATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid)
-        : new MapNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid);
-  }
+  BaseWritableBufferImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MAP | REGION | (readOnly ? READONLY : 0);
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid)
-        : new MapNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid);
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new MapWritableBufferImpl(
+          dirWMap, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableBufferImpl(
+          dirWMap, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes);
+    }
   }
 
   @Override
   BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid)
-        : new MapNonNativeWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid);
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new MapWritableMemoryImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableMemoryImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | DUPLICATE | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new MapWritableBufferImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableBufferImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    }
+  }
+
+  @Override
+  public void close() {
+    checkValid();
+    checkThread(owner);
+    dirWMap.close(); //checksValidAndThread
+  }
+
+  @Override
+  public void force() {
+    checkValid();
+    checkThread(owner);
+    checkNotReadOnly();
+    dirWMap.force(); //checksValidAndThread
+  }
+
+  @Override
+  Object getUnsafeObject() {
     return null;
   }
 
   @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+  public boolean isLoaded() {
+    checkValid();
+    checkThread(owner);
+    return dirWMap.isLoaded(); //checksValidAndThread
   }
 
   @Override
   public boolean isValid() {
-    return valid.get();
+    return dirWMap.getValid().get();
+  }
+
+  @Override
+  public void load() {
+    checkValid();
+    checkThread(owner);
+    dirWMap.load(); //checksValidAndThread
   }
 
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableMemoryImpl.java
index 5305e5f..1801935 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableMemoryImpl.java
@@ -21,7 +21,6 @@
 
 import java.nio.ByteOrder;
 
-import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableMemory;
 
 /**
@@ -31,62 +30,99 @@
  * @author Lee Rhodes
  */
 final class MapNonNativeWritableMemoryImpl extends NonNativeWritableMemoryImpl {
-  private static final int id = MEMORY | NONNATIVE | MAP;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
-  private final StepBoolean valid; //a reference only
-  private final byte typeId;
+  private final AllocateDirectWritableMap dirWMap;
 
   MapNonNativeWritableMemoryImpl(
-      final long nativeBaseOffset,
-      final long regionOffset,
+      final AllocateDirectWritableMap dirWMap,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final StepBoolean valid) {
-    super(null, nativeBaseOffset, regionOffset, capacityBytes);
-    this.nativeBaseOffset = nativeBaseOffset;
-    this.valid = valid;
-    this.typeId = (byte) (id | (typeId & 0x7));
+      final long cumOffsetBytes) {
+    super();
+    this.dirWMap = dirWMap;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | MAP | MEMORY | NONNATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid)
-        : new MapNonNativeWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid);
+  BaseWritableMemoryImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MAP | REGION | (readOnly ? READONLY : 0);
+
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new MapWritableMemoryImpl(
+          dirWMap, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableMemoryImpl(
+          dirWMap, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes);
+    }
   }
 
   @Override
   BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid)
-        : new MapNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid);
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new MapWritableBufferImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableBufferImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
+  public void close() {
+    checkValid();
+    checkThread(owner);
+    dirWMap.close(); //checksValidAndThread
+  }
+
+  @Override
+  public void force() {
+    checkValid();
+    checkThread(owner);
+    checkNotReadOnly();
+    dirWMap.force(); //checksValidAndThread
+  }
+
+  @Override
+  Object getUnsafeObject() {
     return null;
   }
 
   @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+  public boolean isLoaded() {
+    checkValid();
+    checkThread(owner);
+    return dirWMap.isLoaded(); //checksValidAndThread
   }
 
   @Override
   public boolean isValid() {
-    return valid.get();
+    return dirWMap.getValid().get();
+  }
+
+  @Override
+  public void load() {
+    checkValid();
+    checkThread(owner);
+    dirWMap.load(); //checksValidAndThread
   }
 
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapWritableBufferImpl.java
index 9f7c35c..6e12e66 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapWritableBufferImpl.java
@@ -21,7 +21,6 @@
 
 import java.nio.ByteOrder;
 
-import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableBuffer;
 
 /**
@@ -31,72 +30,114 @@
  * @author Lee Rhodes
  */
 final class MapWritableBufferImpl extends NativeWritableBufferImpl {
-  private static final int id = BUFFER | NATIVE | MAP;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
-  private final StepBoolean valid; //a reference only
-  private final byte typeId;
+  private final AllocateDirectWritableMap dirWMap;
 
   MapWritableBufferImpl(
-      final long nativeBaseOffset,
-      final long regionOffset,
+      final AllocateDirectWritableMap dirWMap,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final StepBoolean valid) {
-    super(null, nativeBaseOffset, regionOffset, capacityBytes);
-    this.nativeBaseOffset = nativeBaseOffset;
-    this.valid = valid;
-    this.typeId = (byte) (id | (typeId & 0x7));
+      final long cumOffsetBytes) {
+    super(capacityBytes);
+    this.dirWMap = dirWMap;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | MAP | BUFFER | NATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid)
-        : new MapNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid);
-  }
+  BaseWritableBufferImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MAP | REGION | (readOnly ? READONLY : 0);
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid)
-        : new MapNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid);
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new MapWritableBufferImpl(
+          dirWMap, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableBufferImpl(
+          dirWMap, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes);
+    }
   }
 
   @Override
   BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid)
-        : new MapNonNativeWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid);
+    int typeIdOut = removeNnBuf(typeId) | MEMORY | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new MapWritableMemoryImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableMemoryImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | DUPLICATE | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new MapWritableBufferImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableBufferImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    }
+  }
+
+  @Override
+  public void close() {
+    checkValid();
+    checkThread(owner);
+    dirWMap.close(); //checksValidAndThread
+  }
+
+  @Override
+  public void force() {
+    checkValid();
+    checkThread(owner);
+    checkNotReadOnly();
+    dirWMap.force(); //checksValidAndThread
+  }
+
+  @Override
+  Object getUnsafeObject() {
     return null;
   }
 
   @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+  public boolean isLoaded() {
+    checkValid();
+    checkThread(owner);
+    return dirWMap.isLoaded(); //checksValidAndThread
   }
 
   @Override
   public boolean isValid() {
-    return valid.get();
+    return dirWMap.getValid().get();
+  }
+
+  @Override
+  public void load() {
+    checkValid();
+    checkThread(owner);
+    dirWMap.load(); //checksValidAndThread
   }
 
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapWritableMemoryImpl.java
index 184c1a6..cb9aca2 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MapWritableMemoryImpl.java
@@ -21,7 +21,6 @@
 
 import java.nio.ByteOrder;
 
-import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableMemory;
 
 /**
@@ -31,62 +30,99 @@
  * @author Lee Rhodes
  */
 final class MapWritableMemoryImpl extends NativeWritableMemoryImpl {
-  private static final int id = MEMORY | NATIVE | MAP;
-  private final long nativeBaseOffset; //used to compute cumBaseOffset
-  private final StepBoolean valid; //a reference only
-  private final byte typeId;
+  private final AllocateDirectWritableMap dirWMap;
 
   MapWritableMemoryImpl(
-      final long nativeBaseOffset,
-      final long regionOffset,
+      final AllocateDirectWritableMap dirWMap,
+      final long offsetBytes,
       final long capacityBytes,
       final int typeId,
-      final StepBoolean valid) {
-    super(null, nativeBaseOffset, regionOffset, capacityBytes);
-    this.nativeBaseOffset = nativeBaseOffset;
-    this.valid = valid;
-    this.typeId = (byte) (id | (typeId & 0x7));
+      final long cumOffsetBytes) {
+    super();
+    this.dirWMap = dirWMap;
+    this.offsetBytes = offsetBytes;
+    this.capacityBytes = capacityBytes;
+    this.typeId = removeNnBuf(typeId) | MAP | MEMORY | NATIVE;
+    this.cumOffsetBytes = cumOffsetBytes;
+    if ((this.owner != null) && (this.owner != Thread.currentThread())) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+    this.owner = Thread.currentThread();
   }
 
   @Override
-  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
-      final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | REGION;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid)
-        : new MapNonNativeWritableMemoryImpl(
-            nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, valid);
+  BaseWritableMemoryImpl toWritableRegion(
+      final long regionOffsetBytes,
+      final long capacityBytes,
+      final boolean readOnly,
+      final ByteOrder byteOrder) {
+    final long newOffsetBytes = offsetBytes + regionOffsetBytes;
+    final long newCumOffsetBytes = cumOffsetBytes + regionOffsetBytes;
+    int typeIdOut = removeNnBuf(typeId) | MAP | REGION | (readOnly ? READONLY : 0);
+
+    if (Util.isNativeByteOrder(byteOrder)) {
+      typeIdOut |= NATIVE;
+      return new MapWritableMemoryImpl(
+          dirWMap, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableMemoryImpl(
+          dirWMap, newOffsetBytes, capacityBytes, typeIdOut, newCumOffsetBytes);
+    }
   }
 
   @Override
   BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid)
-        : new MapNonNativeWritableBufferImpl(
-            nativeBaseOffset, getRegionOffset(), getCapacity(), type, valid);
+    int typeIdOut = removeNnBuf(typeId) | BUFFER | (readOnly ? READONLY : 0);
+
+    if (byteOrder == ByteOrder.nativeOrder()) {
+      typeIdOut |= NATIVE;
+      return new MapWritableBufferImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    } else {
+      typeIdOut |= NONNATIVE;
+      return new MapNonNativeWritableBufferImpl(
+          dirWMap, offsetBytes, capacityBytes, typeIdOut, cumOffsetBytes);
+    }
   }
 
   @Override
-  public MemoryRequestServer getMemoryRequestServer() {
+  public void close() {
+    checkValid();
+    checkThread(owner);
+    dirWMap.close();
+  }
+
+  @Override
+  public void force() {
+    checkValid();
+    checkThread(owner);
+    checkNotReadOnly();
+    dirWMap.force(); //checksValidAndThread
+  }
+
+  @Override
+  Object getUnsafeObject() {
     return null;
   }
 
   @Override
-  long getNativeBaseOffset() {
-    return nativeBaseOffset;
-  }
-
-  @Override
-  int getTypeId() {
-    return typeId & 0xff;
+  public boolean isLoaded() {
+    checkValid();
+    checkThread(owner);
+    return dirWMap.isLoaded(); //checksValidAndThread
   }
 
   @Override
   public boolean isValid() {
-    return valid.get();
+    return dirWMap.getValid().get();
+  }
+
+  @Override
+  public void load() {
+    checkValid();
+    checkThread(owner);
+    dirWMap.load(); //checksValidAndThread
   }
 
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MemoryCleaner.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MemoryCleaner.java
index 33053eb..ea3a15c 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MemoryCleaner.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/MemoryCleaner.java
@@ -30,23 +30,22 @@
  */
 @SuppressWarnings("restriction")
 public class MemoryCleaner {
-    private final Cleaner cleaner;
+  private final Cleaner cleaner;
 
-    /**
-     * Creates a new `sun.misc.Cleaner`.
-     * @param referent the object to be cleaned
-     * @param deallocator - the cleanup code to be run when the cleaner is invoked.
-     * return MemoryCleaner
-     */
-    public MemoryCleaner(final Object referent, final Runnable deallocator) {
-        cleaner = Cleaner.create(referent, deallocator);
-    }
+  /**
+   * Creates a new `sun.misc.Cleaner`.
+   * @param referent the object to be cleaned
+   * @param deallocator - the cleanup code to be run when the cleaner is invoked.
+   * return MemoryCleaner
+   */
+  public MemoryCleaner(final Object referent, final Runnable deallocator) {
+    cleaner = Cleaner.create(referent, deallocator);
+  }
 
-    /**
-     * Runs this cleaner, if it has not been run before.
-     */
-    public void clean() {
-        cleaner.clean();
-    }
+  /**
+   * Runs this cleaner, if it has not been run before.
+   */
+  public void clean() {
+    cleaner.clean();
+  }
 }
-
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java
index 2dd1ce2..f092bb3 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java
@@ -27,30 +27,10 @@
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_INT_BASE_OFFSET;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_LONG_BASE_OFFSET;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_SHORT_BASE_OFFSET;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.CHAR_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.DOUBLE_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.FLOAT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.INT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.LONG_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.SHORT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.checkBounds;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
 
 import org.apache.datasketches.memory.WritableBuffer;
 
-/*
- * Developer notes: The heavier methods, such as put/get arrays, duplicate, region, clear, fill,
- * compareTo, etc., use hard checks (check*() and incrementAndCheck*() methods), which execute at
- * runtime and throw exceptions if violated. The cost of the runtime checks are minor compared to
- * the rest of the work these methods are doing.
- *
- * <p>The light weight methods, such as put/get primitives, use asserts (assert*() and
- * incrementAndAssert*() methods), which only execute when asserts are enabled and JIT will remove
- * them entirely from production runtime code. The offset versions of the light weight methods will
- * simplify to a single unsafe call, which is further simplified by JIT to an intrinsic that is
- * often a single CPU instruction.
- */
-
 /**
  * Implementation of {@link WritableBuffer} for native endian byte order.
  * @author Roman Leventov
@@ -59,11 +39,8 @@
 @SuppressWarnings("restriction")
 abstract class NativeWritableBufferImpl extends BaseWritableBufferImpl {
 
-  //Pass-through ctor
-  NativeWritableBufferImpl(final Object unsafeObj, final long nativeBaseOffset, final long regionOffset,
-      final long capacityBytes) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
-  }
+  //Pass-through constructor
+  NativeWritableBufferImpl(final long capacityBytes) { super(capacityBytes); }
 
   //PRIMITIVE getX() and getXArray()
   @Override
@@ -81,7 +58,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthChars) << CHAR_SHIFT;
     incrementAndCheckPositionForRead(pos, copyBytes);
-    checkBounds(dstOffsetChars, lengthChars, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetChars, lengthChars, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             getUnsafeObject(),
             getCumulativeOffset(pos),
@@ -93,13 +70,13 @@
   @Override
   public double getDouble() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_DOUBLE_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_DOUBLE_INDEX_SCALE);
     return unsafe.getDouble(getUnsafeObject(), getCumulativeOffset(pos));
   }
 
   @Override
   public double getDouble(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
     return unsafe.getDouble(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -109,7 +86,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthDoubles) << DOUBLE_SHIFT;
     incrementAndCheckPositionForRead(pos, copyBytes);
-    checkBounds(dstOffsetDoubles, lengthDoubles, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetDoubles, lengthDoubles, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             getUnsafeObject(),
             getCumulativeOffset(pos),
@@ -121,13 +98,13 @@
   @Override
   public float getFloat() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_FLOAT_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_FLOAT_INDEX_SCALE);
     return unsafe.getFloat(getUnsafeObject(), getCumulativeOffset(pos));
   }
 
   @Override
   public float getFloat(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
     return unsafe.getFloat(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -137,7 +114,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthFloats) << FLOAT_SHIFT;
     incrementAndCheckPositionForRead(pos, copyBytes);
-    checkBounds(dstOffsetFloats, lengthFloats, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetFloats, lengthFloats, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             getUnsafeObject(),
             getCumulativeOffset(pos),
@@ -161,7 +138,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthInts) << INT_SHIFT;
     incrementAndCheckPositionForRead(pos, copyBytes);
-    checkBounds(dstOffsetInts, lengthInts, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetInts, lengthInts, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             getUnsafeObject(),
             getCumulativeOffset(pos),
@@ -185,7 +162,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthLongs) << LONG_SHIFT;
     incrementAndCheckPositionForRead(pos, copyBytes);
-    checkBounds(dstOffsetLongs, lengthLongs, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetLongs, lengthLongs, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             getUnsafeObject(),
             getCumulativeOffset(pos),
@@ -210,7 +187,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthShorts) << SHORT_SHIFT;
     incrementAndCheckPositionForRead(pos, copyBytes);
-    checkBounds(dstOffsetShorts, lengthShorts, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetShorts, lengthShorts, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             getUnsafeObject(),
             getCumulativeOffset(pos),
@@ -235,7 +212,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthChars) << CHAR_SHIFT;
     incrementAndCheckPositionForWrite(pos, copyBytes);
-    checkBounds(srcOffsetChars, lengthChars, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetChars, lengthChars, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             srcArray,
             ARRAY_CHAR_BASE_OFFSET + (((long) srcOffsetChars) << CHAR_SHIFT),
@@ -247,13 +224,13 @@
   @Override
   public void putDouble(final double value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_DOUBLE_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_DOUBLE_INDEX_SCALE);
     unsafe.putDouble(getUnsafeObject(), getCumulativeOffset(pos), value);
   }
 
   @Override
   public void putDouble(final long offsetBytes, final double value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
     unsafe.putDouble(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
@@ -263,7 +240,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthDoubles) << DOUBLE_SHIFT;
     incrementAndCheckPositionForWrite(pos, copyBytes);
-    checkBounds(srcOffsetDoubles, lengthDoubles, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetDoubles, lengthDoubles, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             srcArray,
             ARRAY_DOUBLE_BASE_OFFSET + (((long) srcOffsetDoubles) << DOUBLE_SHIFT),
@@ -275,13 +252,13 @@
   @Override
   public void putFloat(final float value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_FLOAT_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_FLOAT_INDEX_SCALE);
     unsafe.putFloat(getUnsafeObject(), getCumulativeOffset(pos), value);
   }
 
   @Override
   public void putFloat(final long offsetBytes, final float value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
     unsafe.putFloat(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
@@ -291,7 +268,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthFloats) << FLOAT_SHIFT;
     incrementAndCheckPositionForWrite(pos, copyBytes);
-    checkBounds(srcOffsetFloats, lengthFloats, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetFloats, lengthFloats, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             srcArray,
             ARRAY_FLOAT_BASE_OFFSET + (((long) srcOffsetFloats) << FLOAT_SHIFT),
@@ -315,7 +292,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthInts) << INT_SHIFT;
     incrementAndCheckPositionForWrite(pos, copyBytes);
-    checkBounds(srcOffsetInts, lengthInts, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetInts, lengthInts, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             srcArray,
             ARRAY_INT_BASE_OFFSET + (((long) srcOffsetInts) << INT_SHIFT),
@@ -339,7 +316,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthLongs) << LONG_SHIFT;
     incrementAndCheckPositionForWrite(pos, copyBytes);
-    checkBounds(srcOffsetLongs, lengthLongs, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetLongs, lengthLongs, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             srcArray,
             ARRAY_LONG_BASE_OFFSET + (((long) srcOffsetLongs) << LONG_SHIFT),
@@ -364,7 +341,7 @@
     final long pos = getPosition();
     final long copyBytes = ((long) lengthShorts) << SHORT_SHIFT;
     incrementAndCheckPositionForWrite(pos, copyBytes);
-    checkBounds(srcOffsetShorts, lengthShorts, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetShorts, lengthShorts, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
             srcArray,
             ARRAY_SHORT_BASE_OFFSET + (((long) srcOffsetShorts) << SHORT_SHIFT),
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImpl.java
index c16423e..922a62d 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImpl.java
@@ -26,31 +26,11 @@
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_FLOAT_INDEX_SCALE;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_INT_BASE_OFFSET;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_LONG_BASE_OFFSET;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_LONG_INDEX_SCALE;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_SHORT_BASE_OFFSET;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.CHAR_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.DOUBLE_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.FLOAT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.INT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.LONG_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.SHORT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.checkBounds;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
 
 import org.apache.datasketches.memory.WritableMemory;
 
-/*
- * Developer notes: The heavier methods, such as put/get arrays, duplicate, region, clear, fill,
- * compareTo, etc., use hard checks (checkValid*() and checkBounds()), which execute at runtime and
- * throw exceptions if violated. The cost of the runtime checks are minor compared to the rest of
- * the work these methods are doing.
- *
- * <p>The light weight methods, such as put/get primitives, use asserts (assertValid*()), which only
- * execute when asserts are enabled and JIT will remove them entirely from production runtime code.
- * The light weight methods will simplify to a single unsafe call, which is further simplified by
- * JIT to an intrinsic that is often a single CPU instruction.
- */
-
 /**
  * Implementation of {@link WritableMemory} for native endian byte order.
  * @author Roman Leventov
@@ -59,11 +39,8 @@
 @SuppressWarnings("restriction")
 abstract class NativeWritableMemoryImpl extends BaseWritableMemoryImpl {
 
-  //Pass-through ctor
-  NativeWritableMemoryImpl(final Object unsafeObj, final long nativeBaseOffset,
-      final long regionOffset, final long capacityBytes) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
-  }
+  //Pass-through constructor
+  NativeWritableMemoryImpl() { }
 
   ///PRIMITIVE getX() and getXArray()
   @Override
@@ -76,7 +53,7 @@
       final int lengthChars) {
     final long copyBytes = ((long) lengthChars) << CHAR_SHIFT;
     checkValidAndBounds(offsetBytes, copyBytes);
-    checkBounds(dstOffsetChars, lengthChars, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetChars, lengthChars, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         getUnsafeObject(),
         getCumulativeOffset(offsetBytes),
@@ -87,7 +64,7 @@
 
   @Override
   public double getDouble(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
     return unsafe.getDouble(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -96,7 +73,7 @@
       final int dstOffsetDoubles, final int lengthDoubles) {
     final long copyBytes = ((long) lengthDoubles) << DOUBLE_SHIFT;
     checkValidAndBounds(offsetBytes, copyBytes);
-    checkBounds(dstOffsetDoubles, lengthDoubles, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetDoubles, lengthDoubles, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         getUnsafeObject(),
         getCumulativeOffset(offsetBytes),
@@ -107,7 +84,7 @@
 
   @Override
   public float getFloat(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
     return unsafe.getFloat(getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
@@ -116,7 +93,7 @@
       final int dstOffsetFloats, final int lengthFloats) {
     final long copyBytes = ((long) lengthFloats) << FLOAT_SHIFT;
     checkValidAndBounds(offsetBytes, copyBytes);
-    checkBounds(dstOffsetFloats, lengthFloats, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetFloats, lengthFloats, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         getUnsafeObject(),
         getCumulativeOffset(offsetBytes),
@@ -135,7 +112,7 @@
       final int lengthInts) {
     final long copyBytes = ((long) lengthInts) << INT_SHIFT;
     checkValidAndBounds(offsetBytes, copyBytes);
-    checkBounds(dstOffsetInts, lengthInts, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetInts, lengthInts, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         getUnsafeObject(),
         getCumulativeOffset(offsetBytes),
@@ -154,7 +131,7 @@
       final int dstOffsetLongs, final int lengthLongs) {
     final long copyBytes = ((long) lengthLongs) << LONG_SHIFT;
     checkValidAndBounds(offsetBytes, copyBytes);
-    checkBounds(dstOffsetLongs, lengthLongs, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetLongs, lengthLongs, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         getUnsafeObject(),
         getCumulativeOffset(offsetBytes),
@@ -173,7 +150,7 @@
       final int dstOffsetShorts, final int lengthShorts) {
     final long copyBytes = ((long) lengthShorts) << SHORT_SHIFT;
     checkValidAndBounds(offsetBytes, copyBytes);
-    checkBounds(dstOffsetShorts, lengthShorts, dstArray.length);
+    ResourceImpl.checkBounds(dstOffsetShorts, lengthShorts, dstArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         getUnsafeObject(),
         getCumulativeOffset(offsetBytes),
@@ -193,7 +170,7 @@
       final int srcOffsetChars, final int lengthChars) {
     final long copyBytes = ((long) lengthChars) << CHAR_SHIFT;
     checkValidAndBoundsForWrite(offsetBytes, copyBytes);
-    checkBounds(srcOffsetChars, lengthChars, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetChars, lengthChars, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         srcArray,
         ARRAY_CHAR_BASE_OFFSET + (((long) srcOffsetChars) << CHAR_SHIFT),
@@ -205,7 +182,7 @@
 
   @Override
   public void putDouble(final long offsetBytes, final double value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
     unsafe.putDouble(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
@@ -214,7 +191,7 @@
       final int srcOffsetDoubles, final int lengthDoubles) {
     final long copyBytes = ((long) lengthDoubles) << DOUBLE_SHIFT;
     checkValidAndBoundsForWrite(offsetBytes, copyBytes);
-    checkBounds(srcOffsetDoubles, lengthDoubles, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetDoubles, lengthDoubles, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         srcArray,
         ARRAY_DOUBLE_BASE_OFFSET + (((long) srcOffsetDoubles) << DOUBLE_SHIFT),
@@ -226,7 +203,7 @@
 
   @Override
   public void putFloat(final long offsetBytes, final float value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
     unsafe.putFloat(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
   }
 
@@ -235,7 +212,7 @@
       final int srcOffsetFloats, final int lengthFloats) {
     final long copyBytes = ((long) lengthFloats) << FLOAT_SHIFT;
     checkValidAndBoundsForWrite(offsetBytes, copyBytes);
-    checkBounds(srcOffsetFloats, lengthFloats, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetFloats, lengthFloats, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         srcArray,
         ARRAY_FLOAT_BASE_OFFSET + (((long) srcOffsetFloats) << FLOAT_SHIFT),
@@ -255,7 +232,7 @@
       final int lengthInts) {
     final long copyBytes = ((long) lengthInts) << INT_SHIFT;
     checkValidAndBoundsForWrite(offsetBytes, copyBytes);
-    checkBounds(srcOffsetInts, lengthInts, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetInts, lengthInts, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         srcArray,
         ARRAY_INT_BASE_OFFSET + (((long) srcOffsetInts) << INT_SHIFT),
@@ -275,7 +252,7 @@
       final int lengthLongs) {
     final long copyBytes = ((long) lengthLongs) << LONG_SHIFT;
     checkValidAndBoundsForWrite(offsetBytes, copyBytes);
-    checkBounds(srcOffsetLongs, lengthLongs, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetLongs, lengthLongs, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         srcArray,
         ARRAY_LONG_BASE_OFFSET + (((long) srcOffsetLongs) << LONG_SHIFT),
@@ -295,7 +272,7 @@
       final int srcOffsetShorts, final int lengthShorts) {
     final long copyBytes = ((long) lengthShorts) << SHORT_SHIFT;
     checkValidAndBoundsForWrite(offsetBytes, copyBytes);
-    checkBounds(srcOffsetShorts, lengthShorts, srcArray.length);
+    ResourceImpl.checkBounds(srcOffsetShorts, lengthShorts, srcArray.length);
     CompareAndCopy.copyMemoryCheckingDifferentObject(
         srcArray,
         ARRAY_SHORT_BASE_OFFSET + (((long) srcOffsetShorts) << SHORT_SHIFT),
@@ -305,26 +282,4 @@
     );
   }
 
-  //Atomic Write Methods
-  @Override
-  public long getAndAddLong(final long offsetBytes, final long delta) { //JDK 8+
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
-    final long addr = getCumulativeOffset(offsetBytes);
-    return unsafe.getAndAddLong(getUnsafeObject(), addr, delta);
-  }
-
-  @Override
-  public long getAndSetLong(final long offsetBytes, final long newValue) { //JDK 8+
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
-    final long addr = getCumulativeOffset(offsetBytes);
-    return unsafe.getAndSetLong(getUnsafeObject(), addr, newValue);
-  }
-
-  @Override
-  public boolean compareAndSwapLong(final long offsetBytes, final long expect, final long update) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
-    return unsafe.compareAndSwapLong(
-        getUnsafeObject(), getCumulativeOffset(offsetBytes), expect, update);
-  }
-
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NioBits.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NioBits.java
deleted file mode 100644
index 62827ac..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NioBits.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Provide linkage to java.nio.Bits.
- *
- * @author Lee Rhodes
- */
-@SuppressWarnings("restriction")
-final class NioBits {
-  private static final Class<?> NIO_BITS_CLASS;
-  private static final Method NIO_BITS_RESERVE_MEMORY_METHOD;
-  private static final Method NIO_BITS_UNRESERVE_MEMORY_METHOD;
-
-  private static final AtomicLong nioBitsCount;
-  private static final AtomicLong nioBitsReservedMemory;
-  private static final AtomicLong nioBitsTotalCapacity;
-
-  private static int pageSize = unsafe.pageSize();
-  private static final long maxDBBMemory;
-  private static final boolean isPageAligned;
-
-  static {
-    try {
-      isPageAligned = VirtualMachineMemory.getIsPageAligned();
-      maxDBBMemory = VirtualMachineMemory.getMaxDBBMemory();
-
-      NIO_BITS_CLASS = Class.forName("java.nio.Bits");
-
-      NIO_BITS_RESERVE_MEMORY_METHOD = NIO_BITS_CLASS
-          .getDeclaredMethod("reserveMemory", long.class, int.class); //JD16 requires (long, long)
-      NIO_BITS_RESERVE_MEMORY_METHOD.setAccessible(true);
-
-      NIO_BITS_UNRESERVE_MEMORY_METHOD = NIO_BITS_CLASS
-          .getDeclaredMethod("unreserveMemory", long.class, int.class); //JD16 requires (long, long)
-      NIO_BITS_UNRESERVE_MEMORY_METHOD.setAccessible(true);
-
-      final Field countField = NIO_BITS_CLASS.getDeclaredField(NioBitsFields.COUNT_FIELD_NAME);
-      countField.setAccessible(true);
-      nioBitsCount = (AtomicLong) (countField.get(null));
-
-      final Field reservedMemoryField = NIO_BITS_CLASS.getDeclaredField(NioBitsFields.RESERVED_MEMORY_FIELD_NAME);
-      reservedMemoryField.setAccessible(true);
-      nioBitsReservedMemory = (AtomicLong) (reservedMemoryField.get(null));
-
-      final Field totalCapacityField = NIO_BITS_CLASS.getDeclaredField(NioBitsFields.TOTAL_CAPACITY_FIELD_NAME);
-      totalCapacityField.setAccessible(true);
-      nioBitsTotalCapacity = (AtomicLong) (totalCapacityField.get(null));
-
-    } catch (final ClassNotFoundException | NoSuchMethodException |  IllegalAccessException
-        | IllegalArgumentException | SecurityException |  NoSuchFieldException e) {
-      throw new RuntimeException("Could not acquire java.nio.Bits class: " + e.getClass());
-    }
-  }
-
-  private NioBits() { }
-
-  static long getDirectAllocationsCount() { //tested via reflection
-    return nioBitsCount.get();
-  }
-
-  static long getReservedMemory() { //tested via reflection
-    return nioBitsReservedMemory.get();
-  }
-
-  static long getTotalCapacity() { //tested via reflection
-    return nioBitsTotalCapacity.get();
-  }
-
-  static int pageSize() {
-    return pageSize;
-  }
-
-  static int pageCount(final long bytes) {
-    return (int)((bytes + pageSize()) - 1L) / pageSize();
-  }
-
-  static long getMaxDirectByteBufferMemory() { //tested via reflection
-    return maxDBBMemory;
-  }
-
-  static boolean isPageAligned() {
-    return isPageAligned;
-  }
-
-  //RESERVE & UNRESERVE BITS MEMORY TRACKING COUNTERS
-  // Comment from java.nio.Bits.java ~ line 705:
-  // -XX:MaxDirectMemorySize limits the total capacity rather than the
-  // actual memory usage, which will differ when buffers are page aligned.
-  static void reserveMemory(final long allocationSize, final long capacity) {
-    reserveUnreserve(allocationSize, capacity, NIO_BITS_RESERVE_MEMORY_METHOD);
-  }
-
-  static void unreserveMemory(final long allocationSize, final long capacity) {
-    reserveUnreserve(allocationSize, capacity, NIO_BITS_UNRESERVE_MEMORY_METHOD);
-  }
-
-  private static void reserveUnreserve(long allocationSize, long capacity, final Method method) {
-    Util.zeroCheck(capacity, "capacity");
-    // 1GB is a pretty "safe" limit.
-    final long chunkSizeLimit = 1L << 30;
-    try {
-      while (capacity > 0) {
-        final long chunk = Math.min(capacity, chunkSizeLimit);
-        if (capacity == chunk) {
-          method.invoke(null, allocationSize, (int) capacity); //JDK 16 remove cast to int
-        } else {
-          method.invoke(null, chunk, (int) chunk); //JDK 16 remove cast to int
-        }
-        capacity -= chunk;
-        allocationSize -= chunk;
-      }
-    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-      throw new RuntimeException(
-          "Could not invoke java.nio.Bits.unreserveMemory(...) OR java.nio.Bits.reserveMemory(...): "
-          + "allocationSize = " + allocationSize + ", capacity = " + capacity, e);
-    }
-  }
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NioBitsFields.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NioBitsFields.java
deleted file mode 100644
index 56f1e20..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NioBitsFields.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-/**
- * Extracts version-dependent field names into standalone class.
- * Some field names in the VM internal class have changed in
- * later versions. The appropriate class will be loaded by the class loader
- * depending on the Java version that is used.
- * For more information, see: https://openjdk.java.net/jeps/238
- */
-class NioBitsFields {
-    static String COUNT_FIELD_NAME = "count";
-    static String RESERVED_MEMORY_FIELD_NAME = "reservedMemory";
-    static String TOTAL_CAPACITY_FIELD_NAME = "totalCapacity";
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImpl.java
index a8203ba..8202ebf 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImpl.java
@@ -21,29 +21,10 @@
 
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_DOUBLE_INDEX_SCALE;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_FLOAT_INDEX_SCALE;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.CHAR_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.DOUBLE_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.FLOAT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.INT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.LONG_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.SHORT_SHIFT;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
 
 import org.apache.datasketches.memory.WritableBuffer;
 
-/*
- * Developer notes: The heavier methods, such as put/get arrays, duplicate, region, clear, fill,
- * compareTo, etc., use hard checks (check*() and incrementAndCheck*() methods), which execute at
- * runtime and throw exceptions if violated. The cost of the runtime checks are minor compared to
- * the rest of the work these methods are doing.
- *
- * <p>The light weight methods, such as put/get primitives, use asserts (assert*() and
- * incrementAndAssert*() methods), which only execute when asserts are enabled and JIT will remove
- * them entirely from production runtime code. The offset versions of the light weight methods will
- * simplify to a single unsafe call, which is further simplified by JIT to an intrinsic that is
- * often a single CPU instruction.
- */
-
 /**
  * Implementation of {@link WritableBuffer} for non-native endian byte order.
  * @author Roman Leventov
@@ -52,11 +33,8 @@
 @SuppressWarnings("restriction")
 abstract class NonNativeWritableBufferImpl extends BaseWritableBufferImpl {
 
-  //Pass-through ctor
-  NonNativeWritableBufferImpl(final Object unsafeObj, final long nativeBaseOffset, final long regionOffset,
-      final long capacityBytes) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
-  }
+  //Pass-through constructor
+  NonNativeWritableBufferImpl(final long capacityBytes) { super(capacityBytes); }
 
   //PRIMITIVE getX() and getXArray()
   @Override
@@ -81,14 +59,14 @@
   @Override
   public double getDouble() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_DOUBLE_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_DOUBLE_INDEX_SCALE);
     return Double.longBitsToDouble(
         Long.reverseBytes(unsafe.getLong(getUnsafeObject(), getCumulativeOffset(pos))));
   }
 
   @Override
   public double getDouble(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
     return Double.longBitsToDouble(
         Long.reverseBytes(unsafe.getLong(getUnsafeObject(), getCumulativeOffset(offsetBytes))));
   }
@@ -106,14 +84,14 @@
   @Override
   public float getFloat() {
     final long pos = getPosition();
-    incrementAndAssertPositionForRead(pos, ARRAY_FLOAT_INDEX_SCALE);
+    incrementAndCheckPositionForRead(pos, ARRAY_FLOAT_INDEX_SCALE);
     return Float.intBitsToFloat(
         Integer.reverseBytes(unsafe.getInt(getUnsafeObject(), getCumulativeOffset(pos))));
   }
 
   @Override
   public float getFloat(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
     return Float.intBitsToFloat(
         Integer.reverseBytes(unsafe.getInt(getUnsafeObject(), getCumulativeOffset(offsetBytes))));
   }
@@ -209,14 +187,14 @@
   @Override
   public void putDouble(final double value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_DOUBLE_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_DOUBLE_INDEX_SCALE);
     unsafe.putLong(getUnsafeObject(), getCumulativeOffset(pos),
         Long.reverseBytes(Double.doubleToRawLongBits(value)));
   }
 
   @Override
   public void putDouble(final long offsetBytes, final double value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
     unsafe.putLong(getUnsafeObject(), getCumulativeOffset(offsetBytes),
         Long.reverseBytes(Double.doubleToRawLongBits(value)));
   }
@@ -234,14 +212,14 @@
   @Override
   public void putFloat(final float value) {
     final long pos = getPosition();
-    incrementAndAssertPositionForWrite(pos, ARRAY_FLOAT_INDEX_SCALE);
+    incrementAndCheckPositionForWrite(pos, ARRAY_FLOAT_INDEX_SCALE);
     unsafe.putInt(getUnsafeObject(), getCumulativeOffset(pos),
         Integer.reverseBytes(Float.floatToRawIntBits(value)));
   }
 
   @Override
   public void putFloat(final long offsetBytes, final float value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
     unsafe.putInt(getUnsafeObject(), getCumulativeOffset(offsetBytes),
         Integer.reverseBytes(Float.floatToRawIntBits(value)));
   }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImpl.java
index de74333..8597ce5 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImpl.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImpl.java
@@ -21,29 +21,10 @@
 
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_DOUBLE_INDEX_SCALE;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_FLOAT_INDEX_SCALE;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_LONG_INDEX_SCALE;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.CHAR_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.DOUBLE_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.FLOAT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.INT_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.LONG_SHIFT;
-import static org.apache.datasketches.memory.internal.UnsafeUtil.SHORT_SHIFT;
 import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
 
 import org.apache.datasketches.memory.WritableMemory;
 
-/*
- * Developer notes: The heavier methods, such as put/get arrays, duplicate, region, clear, fill,
- * compareTo, etc., use hard checks (checkValid*() and checkBounds()), which execute at runtime and
- * throw exceptions if violated. The cost of the runtime checks are minor compared to the rest of
- * the work these methods are doing.
- *
- * <p>The light weight methods, such as put/get primitives, use asserts (assertValid*()), which only
- * execute when asserts are enabled and JIT will remove them entirely from production runtime code.
- * The light weight methods will simplify to a single unsafe call, which is further simplified by
- * JIT to an intrinsic that is often a single CPU instruction.
- */
-
 /**
  * Implementation of {@link WritableMemory} for non-native endian byte order.
  * @author Roman Leventov
@@ -52,11 +33,8 @@
 @SuppressWarnings("restriction")
 abstract class NonNativeWritableMemoryImpl extends BaseWritableMemoryImpl {
 
-  //Pass-through ctor
-  NonNativeWritableMemoryImpl(final Object unsafeObj, final long nativeBaseOffset,
-      final long regionOffset, final long capacityBytes) {
-    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
-  }
+  //Pass-through constructor
+  NonNativeWritableMemoryImpl() { }
 
   ///PRIMITIVE getX() and getXArray()
   @Override
@@ -75,7 +53,7 @@
 
   @Override
   public double getDouble(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
     return Double.longBitsToDouble(
         Long.reverseBytes(unsafe.getLong(getUnsafeObject(), getCumulativeOffset(offsetBytes))));
   }
@@ -91,7 +69,7 @@
 
   @Override
   public float getFloat(final long offsetBytes) {
-    assertValidAndBoundsForRead(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
+    checkValidAndBounds(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
     return Float.intBitsToFloat(
         Integer.reverseBytes(unsafe.getInt(getUnsafeObject(), getCumulativeOffset(offsetBytes))));
   }
@@ -164,7 +142,7 @@
 
   @Override
   public void putDouble(final long offsetBytes, final double value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_DOUBLE_INDEX_SCALE);
     unsafe.putLong(getUnsafeObject(), getCumulativeOffset(offsetBytes),
         Long.reverseBytes(Double.doubleToRawLongBits(value)));
   }
@@ -180,7 +158,7 @@
 
   @Override
   public void putFloat(final long offsetBytes, final float value) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
+    checkValidAndBoundsForWrite(offsetBytes, ARRAY_FLOAT_INDEX_SCALE);
     unsafe.putInt(getUnsafeObject(), getCumulativeOffset(offsetBytes),
         Integer.reverseBytes(Float.floatToRawIntBits(value)));
   }
@@ -236,34 +214,4 @@
         getUnsafeObject(), getCumulativeOffset(offsetBytes));
   }
 
-  //Atomic Write Methods
-  @Override
-  public long getAndAddLong(final long offsetBytes, final long delta) { //JDK 8+
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
-    final long addr = getCumulativeOffset(offsetBytes);
-    long oldValReverseBytes, oldVal, newValReverseBytes;
-    final Object unsafeObj = getUnsafeObject();
-    do {
-      oldValReverseBytes = unsafe.getLongVolatile(unsafeObj, addr);
-      oldVal = Long.reverseBytes(oldValReverseBytes);
-      newValReverseBytes = Long.reverseBytes(oldVal + delta);
-    } while (!unsafe.compareAndSwapLong(unsafeObj, addr, oldValReverseBytes, newValReverseBytes));
-
-    return oldVal;
-  }
-
-  @Override
-  public long getAndSetLong(final long offsetBytes, final long newValue) { //JDK 8+
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
-    final long addr = getCumulativeOffset(offsetBytes);
-    final long newValueReverseBytes = Long.reverseBytes(newValue);
-    return Long.reverseBytes(unsafe.getAndSetLong(getUnsafeObject(), addr, newValueReverseBytes));
-  }
-
-  @Override
-  public boolean compareAndSwapLong(final long offsetBytes, final long expect, final long update) {
-    assertValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
-    return unsafe.compareAndSwapLong(getUnsafeObject(), getCumulativeOffset(offsetBytes),
-        Long.reverseBytes(expect), Long.reverseBytes(update));
-  }
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java
new file mode 100644
index 0000000..2f4796b
--- /dev/null
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java
@@ -0,0 +1,524 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
+import static org.apache.datasketches.memory.internal.Util.characterPad;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryBoundsException;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.Resource;
+
+/**
+ * Implements the root Resource methods.
+ *
+ * @author Lee Rhodes
+ */
+@SuppressWarnings("restriction")
+public abstract class ResourceImpl implements Resource {
+  static final String JDK; //must be at least "1.8"
+  static final int JDK_MAJOR; //8, 11, 17, etc
+
+  //Used to convert "type" to bytes:  bytes = longs << LONG_SHIFT
+  static final int BOOLEAN_SHIFT    = 0;
+  static final int BYTE_SHIFT       = 0;
+  static final long SHORT_SHIFT     = 1;
+  static final long CHAR_SHIFT      = 1;
+  static final long INT_SHIFT       = 2;
+  static final long LONG_SHIFT      = 3;
+  static final long FLOAT_SHIFT     = 2;
+  static final long DOUBLE_SHIFT    = 3;
+
+  //class type IDs. Do not change the bit orders
+  //The lowest 3 bits are set dynamically
+  // 0000 0XXX Group 1
+  static final int WRITABLE = 0;
+  static final int READONLY = 1;
+  static final int REGION = 1 << 1;
+  static final int DUPLICATE = 1 << 2; //for Buffer only
+
+  // 000X X000 Group 2
+  static final int HEAP = 0;
+  static final int DIRECT = 1 << 3;
+  static final int MAP = 1 << 4; //Map is always Direct also
+
+  // 00X0 0000 Group 3
+  static final int NATIVE = 0;
+  static final int NONNATIVE = 1 << 5;
+
+  // 0X00 0000 Group 4
+  static final int MEMORY = 0;
+  static final int BUFFER = 1 << 6;
+
+  // X000 0000 Group 5
+  static final int BYTEBUF = 1 << 7;
+
+  /**
+   * The java line separator character as a String.
+   */
+  public static final String LS = System.getProperty("line.separator");
+
+  public static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder();
+
+  public static final ByteOrder NON_NATIVE_BYTE_ORDER =
+      (NATIVE_BYTE_ORDER == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
+
+  static final String NOT_MAPPED_FILE_RESOURCE = "This is not a memory-mapped file resource";
+  static final String THREAD_EXCEPTION_TEXT = "Attempted access outside owning thread";
+
+  static {
+    final String jdkVer = System.getProperty("java.version");
+    final int[] p = parseJavaVersion(jdkVer);
+    JDK = p[0] + "." + p[1];
+    JDK_MAJOR = (p[0] == 1) ? p[1] : p[0];
+  }
+
+  //set by the leaf nodes
+  long capacityBytes;
+  long cumOffsetBytes;
+  long offsetBytes;
+  int typeId;
+  MemoryRequestServer memReqSvr = null; //set by the user via the leaf nodes
+  Thread owner = null;
+
+  /**
+   * The root of the Memory inheritance hierarchy
+   */
+  ResourceImpl() { }
+
+  /**
+   * Check the requested offset and length against the allocated size.
+   * The invariants equation is: {@code 0 <= reqOff <= reqLen <= reqOff + reqLen <= allocSize}.
+   * If this equation is violated an {@link MemoryBoundsException} will be thrown.
+   * @param reqOff the requested offset
+   * @param reqLen the requested length
+   * @param allocSize the allocated size.
+   * @Throws MemoryBoundsException if the given arguments constitute a violation
+   * of the invariants equation expressed above.
+   */
+  public static void checkBounds(final long reqOff, final long reqLen, final long allocSize) {
+    if ((reqOff | reqLen | (reqOff + reqLen) | (allocSize - (reqOff + reqLen))) < 0) {
+      throw new MemoryBoundsException(
+          "reqOffset: " + reqOff + ", reqLength: " + reqLen
+              + ", (reqOff + reqLen): " + (reqOff + reqLen) + ", allocSize: " + allocSize);
+    }
+  }
+
+  static void checkJavaVersion(final String jdkVer, final int p0, final int p1 ) {
+    final boolean ok = ((p0 == 1) && (p1 == 8)) || (p0 == 8) || (p0 == 11) || (p0 == 17);
+    if (!ok) { throw new IllegalArgumentException(
+        "Unsupported JDK Major Version. It must be one of 1.8, 8, 11, 17: " + jdkVer);
+    }
+  }
+
+  void checkNotReadOnly() {
+    if (isReadOnly()) {
+      throw new ReadOnlyException("Cannot write to a read-only Resource.");
+    }
+  }
+
+  /**
+   * This checks that the current thread is the same as the given owner thread.
+   * @Throws IllegalStateException if it is not.
+   * @param owner the given owner thread.
+   */
+  static final void checkThread(final Thread owner) {
+    if (owner != Thread.currentThread()) {
+      throw new IllegalStateException(THREAD_EXCEPTION_TEXT);
+    }
+  }
+
+  /**
+   * @throws IllegalStateException if this Resource is AutoCloseable, and already closed, i.e., not <em>valid</em>.
+   */
+  void checkValid() {
+    if (!isValid()) {
+      throw new IllegalStateException("this Resource is AutoCloseable, and already closed, i.e., not <em>valid</em>.");
+    }
+  }
+
+  /**
+   * Checks that this resource is still valid and throws a MemoryInvalidException if it is not.
+   * Checks that the specified range of bytes is within bounds of this resource, throws
+   * {@link MemoryBoundsException} if it's not: i. e. if offsetBytes &lt; 0, or length &lt; 0,
+   * or offsetBytes + length &gt; {@link #getCapacity()}.
+   * @param offsetBytes the given offset in bytes of this object
+   * @param lengthBytes the given length in bytes of this object
+   * @Throws MemoryInvalidException if this resource is AutoCloseable and is no longer valid, i.e.,
+   * it has already been closed.
+   * @Throws MemoryBoundsException if this resource violates the memory bounds of this resource.
+   */
+  public final void checkValidAndBounds(final long offsetBytes, final long lengthBytes) {
+    checkValid();
+    checkBounds(offsetBytes, lengthBytes, getCapacity());
+  }
+
+  /**
+   * Checks that this resource is still valid and throws a MemoryInvalidException if it is not.
+   * Checks that the specified range of bytes is within bounds of this resource, throws
+   * {@link MemoryBoundsException} if it's not: i. e. if offsetBytes &lt; 0, or length &lt; 0,
+   * or offsetBytes + length &gt; {@link #getCapacity()}.
+   * Checks that this operation is a read-only operation and throws a ReadOnlyException if not.
+   * @param offsetBytes the given offset in bytes of this object
+   * @param lengthBytes the given length in bytes of this object
+   * @Throws MemoryInvalidException if this resource is AutoCloseable and is no longer valid, i.e.,
+   * it has already been closed.
+   * @Throws MemoryBoundsException if this resource violates the memory bounds of this resource.
+   * @Throws ReadOnlyException if the associated operation is not a Read-only operation.
+   */
+  final void checkValidAndBoundsForWrite(final long offsetBytes, final long lengthBytes) {
+    checkValid();
+    checkBounds(offsetBytes, lengthBytes, getCapacity());
+    if (isReadOnly()) {
+      throw new ReadOnlyException("Memory is read-only.");
+    }
+  }
+
+  @Override
+  public void close() {
+    /* Overridden by the actual AutoCloseable leaf sub-classes. */
+    throw new UnsupportedOperationException("This resource is not AutoCloseable.");
+  }
+
+  @Override
+  public final boolean equalTo(final long thisOffsetBytes, final Resource that,
+      final long thatOffsetBytes, final long lengthBytes) {
+    if (that == null) { return false; }
+    return CompareAndCopy.equals(this, thisOffsetBytes, (ResourceImpl) that, thatOffsetBytes, lengthBytes);
+  }
+
+  @Override
+  public void force() { //overridden by Map Leaves
+    throw new UnsupportedOperationException(NOT_MAPPED_FILE_RESOURCE);
+  }
+
+  //Overridden by ByteBuffer Leaves. Used internally and for tests.
+  ByteBuffer getByteBuffer() {
+    return null;
+  }
+
+  @Override
+  public final ByteOrder getByteOrder() {
+    return isNativeOrder(getTypeId()) ? NATIVE_BYTE_ORDER : NON_NATIVE_BYTE_ORDER;
+  }
+
+  @Override
+  public long getCapacity() {
+    checkValid();
+    return capacityBytes;
+  }
+
+  /**
+   * Gets the cumulative offset in bytes of this object from the backing resource including the given
+   * localOffsetBytes. This offset may also include other offset components such as the native off-heap
+   * memory address, DirectByteBuffer split offsets, region offsets, and object arrayBaseOffsets.
+   *
+   * @param addOffsetBytes offset to be added to the cumulative offset.
+   * @return the cumulative offset in bytes of this object from the backing resource including the
+   * given offsetBytes.
+   */
+  long getCumulativeOffset(final long addOffsetBytes) {
+    return cumOffsetBytes + addOffsetBytes;
+  }
+
+  @Override
+  public MemoryRequestServer getMemoryRequestServer() { return memReqSvr; }
+
+  @Override
+  public long getTotalOffset() {
+    return offsetBytes;
+  }
+
+  //Overridden by all leaves
+  int getTypeId() {
+    return typeId;
+  }
+
+  //Overridden by Heap and ByteBuffer leaves. Made public as getArray() in WritableMemoryImpl and
+  // WritableBufferImpl
+  Object getUnsafeObject() {
+    return null;
+  }
+
+  @Override
+  public boolean isByteBufferResource() {
+    return (getTypeId() & BYTEBUF) > 0;
+  }
+
+  @Override
+  public final boolean isByteOrderCompatible(final ByteOrder byteOrder) {
+    final ByteOrder typeBO = getByteOrder();
+    return typeBO == ByteOrder.nativeOrder() && typeBO == byteOrder;
+  }
+
+  final boolean isBufferApi(final int typeId) {
+    return (typeId & BUFFER) > 0;
+  }
+
+  @Override
+  public final boolean isDirectResource() {
+    return getUnsafeObject() == null;
+  }
+
+  @Override
+  public boolean isDuplicateBufferView() {
+    return (getTypeId() & DUPLICATE) > 0;
+  }
+
+  @Override
+  public final boolean isHeapResource() {
+    checkValid();
+    return getUnsafeObject() != null;
+  }
+
+  @Override
+  public boolean isLoaded() { //overridden by Map Leaves
+    throw new IllegalStateException(NOT_MAPPED_FILE_RESOURCE);
+  }
+
+  @Override
+  public boolean isMemoryMappedResource() {
+    return (getTypeId() & MAP) > 0;
+  }
+
+  @Override
+  public boolean isMemoryApi() {
+    return (getTypeId() & BUFFER) == 0;
+  }
+
+  final boolean isNativeOrder(final int typeId) { //not used
+    return (typeId & NONNATIVE) == 0;
+  }
+
+  @Override
+  public boolean isNonNativeOrder() {
+    return (getTypeId() & NONNATIVE) > 0;
+  }
+
+  @Override
+  public final boolean isReadOnly() {
+    checkValid();
+    return (getTypeId() & READONLY) > 0;
+  }
+
+  @Override
+  public boolean isRegionView() {
+    return (getTypeId() & REGION) > 0;
+  }
+
+  @Override
+  public boolean isSameResource(final Resource that) {
+    checkValid();
+    if (that == null) { return false; }
+    final ResourceImpl that1 = (ResourceImpl) that;
+    that1.checkValid();
+    if (this == that1) { return true; }
+    return getCumulativeOffset(0) == that1.getCumulativeOffset(0)
+            && getCapacity() == that1.getCapacity()
+            && getUnsafeObject() == that1.getUnsafeObject()
+            && getByteBuffer() == that1.getByteBuffer();
+  }
+
+  //Overridden by Direct and Map leaves
+  @Override
+  public boolean isValid() {
+    return true;
+  }
+
+  @Override
+  public void load() { //overridden by Map leaves
+    throw new IllegalStateException(NOT_MAPPED_FILE_RESOURCE);
+  }
+
+  private static String pad(final String s, final int fieldLen) {
+    return characterPad(s, fieldLen, ' ' , true);
+  }
+
+  /**
+   * Returns first two number groups of the java version string.
+   * @param jdkVer the java version string from System.getProperty("java.version").
+   * @return first two number groups of the java version string.
+   * @throws IllegalArgumentException for an improper Java version string.
+   */
+  static int[] parseJavaVersion(final String jdkVer) {
+    final int p0, p1;
+    try {
+      String[] parts = jdkVer.trim().split("^0-9\\.");//grab only number groups and "."
+      parts = parts[0].split("\\."); //split out the number groups
+      p0 = Integer.parseInt(parts[0]); //the first number group
+      p1 = (parts.length > 1) ? Integer.parseInt(parts[1]) : 0; //2nd number group, or 0
+    } catch (final NumberFormatException | ArrayIndexOutOfBoundsException  e) {
+      throw new IllegalArgumentException("Improper Java -version string: " + jdkVer + "\n" + e);
+    }
+    checkJavaVersion(jdkVer, p0, p1);
+    return new int[] {p0, p1};
+  }
+
+  //REACHABILITY FENCE
+  static void reachabilityFence(final Object obj) { }
+
+  final static int removeNnBuf(final int typeId) { return typeId & ~NONNATIVE & ~BUFFER; }
+
+  final static int setReadOnlyBit(final int typeId, final boolean readOnly) {
+    return readOnly ? typeId | READONLY : typeId & ~READONLY;
+  }
+
+  @Override
+  public void setMemoryRequestServer(final MemoryRequestServer memReqSvr) { this.memReqSvr = memReqSvr; }
+
+  /**
+   * Returns a formatted hex string of an area of this object.
+   * Used primarily for testing.
+   * @param state the ResourceImpl
+   * @param preamble a descriptive header
+   * @param offsetBytes offset bytes relative to the MemoryImpl start
+   * @param lengthBytes number of bytes to convert to a hex string
+   * @return a formatted hex string in a human readable array
+   */
+  static final String toHex(final ResourceImpl state, final String preamble, final long offsetBytes,
+      final int lengthBytes) {
+    final long capacity = state.getCapacity();
+    ResourceImpl.checkBounds(offsetBytes, lengthBytes, capacity);
+    final StringBuilder sb = new StringBuilder();
+    final Object uObj = state.getUnsafeObject();
+    final String uObjStr;
+    final long uObjHeader;
+    if (uObj == null) {
+      uObjStr = "null";
+      uObjHeader = 0;
+    } else {
+      uObjStr =  uObj.getClass().getSimpleName() + ", " + (uObj.hashCode() & 0XFFFFFFFFL);
+      uObjHeader = UnsafeUtil.getArrayBaseOffset(uObj.getClass());
+    }
+    final ByteBuffer bb = state.getByteBuffer();
+    final String bbStr = bb == null ? "null"
+            : bb.getClass().getSimpleName() + ", " + (bb.hashCode() & 0XFFFFFFFFL);
+    final MemoryRequestServer memReqSvr = state.getMemoryRequestServer();
+    final String memReqStr = memReqSvr != null
+        ? memReqSvr.getClass().getSimpleName() + ", " + (memReqSvr.hashCode() & 0XFFFFFFFFL)
+        : "null";
+    final long cumBaseOffset = state.getCumulativeOffset(0);
+    sb.append(preamble).append(LS);
+    sb.append("UnsafeObj, hashCode : ").append(uObjStr).append(LS);
+    sb.append("UnsafeObjHeader     : ").append(uObjHeader).append(LS);
+    sb.append("ByteBuf, hashCode   : ").append(bbStr).append(LS);
+    sb.append("RegionOffset        : ").append(state.getTotalOffset()).append(LS);
+    sb.append("Capacity            : ").append(capacity).append(LS);
+    sb.append("CumBaseOffset       : ").append(cumBaseOffset).append(LS);
+    sb.append("MemReq, hashCode    : ").append(memReqStr).append(LS);
+    sb.append("Valid               : ").append(state.isValid()).append(LS);
+    sb.append("Read Only           : ").append(state.isReadOnly()).append(LS);
+    sb.append("Type Byte Order     : ").append(state.getByteOrder().toString()).append(LS);
+    sb.append("Native Byte Order   : ").append(ByteOrder.nativeOrder().toString()).append(LS);
+    sb.append("JDK Runtime Version : ").append(UnsafeUtil.JDK).append(LS);
+    //Data detail
+    sb.append("Data, littleEndian  :  0  1  2  3  4  5  6  7");
+
+    for (long i = 0; i < lengthBytes; i++) {
+      final int b = unsafe.getByte(uObj, cumBaseOffset + offsetBytes + i) & 0XFF;
+      if (i % 8 == 0) { //row header
+        sb.append(String.format("%n%20s: ", offsetBytes + i));
+      }
+      sb.append(String.format("%02x ", b));
+    }
+    sb.append(LS);
+
+    return sb.toString();
+  }
+
+  @Override
+  public final String toHexString(final String header, final long offsetBytes,
+      final int lengthBytes) {
+    checkValid();
+    final String klass = this.getClass().getSimpleName();
+    final String s1 = String.format("(..., %d, %d)", offsetBytes, lengthBytes);
+    final long hcode = hashCode() & 0XFFFFFFFFL;
+    final String call = ".toHexString" + s1 + ", hashCode: " + hcode;
+    final StringBuilder sb = new StringBuilder();
+    sb.append("### ").append(klass).append(" SUMMARY ###").append(LS);
+    sb.append("Header Comment      : ").append(header).append(LS);
+    sb.append("Call Parameters     : ").append(call);
+    return toHex(this, sb.toString(), offsetBytes, lengthBytes);
+  }
+
+  /**
+   * Decodes the resource type. This is primarily for debugging.
+   * @param typeId the given typeId
+   * @return a human readable string.
+   */
+  static final String typeDecode(final int typeId) {
+    final StringBuilder sb = new StringBuilder();
+    final int group1 = typeId & 0x7;
+    switch (group1) { // 0000 0XXX
+      case 0 : sb.append(pad("Writable + ",32)); break;
+      case 1 : sb.append(pad("ReadOnly + ",32)); break;
+      case 2 : sb.append(pad("Writable + Region + ",32)); break;
+      case 3 : sb.append(pad("ReadOnly + Region + ",32)); break;
+      case 4 : sb.append(pad("Writable + Duplicate + ",32)); break;
+      case 5 : sb.append(pad("ReadOnly + Duplicate + ",32)); break;
+      case 6 : sb.append(pad("Writable + Region + Duplicate + ",32)); break;
+      case 7 : sb.append(pad("ReadOnly + Region + Duplicate + ",32)); break;
+      default: break;
+    }
+    final int group2 = (typeId >>> 3) & 0x3;
+    switch (group2) { // 000X X000
+      case 0 : sb.append(pad("Heap + ",15)); break;
+      case 1 : sb.append(pad("Direct + ",15)); break;
+      case 2 : sb.append(pad("Map + Direct + ",15)); break;
+      case 3 : sb.append(pad("Map + Direct + ",15)); break;
+      default: break;
+    }
+    final int group3 = (typeId >>> 5) & 0x1;
+    switch (group3) { // 00X0 0000
+      case 0 : sb.append(pad("NativeOrder + ",17)); break;
+      case 1 : sb.append(pad("NonNativeOrder + ",17)); break;
+      default: break;
+    }
+    final int group4 = (typeId >>> 6) & 0x1;
+    switch (group4) { // 0X00 0000
+      case 0 : sb.append(pad("Memory + ",9)); break;
+      case 1 : sb.append(pad("Buffer + ",9)); break;
+      default: break;
+    }
+    final int group5 = (typeId >>> 7) & 0x1;
+    switch (group5) { // X000 0000
+      case 0 : sb.append(pad("",10)); break;
+      case 1 : sb.append(pad("ByteBuffer",10)); break;
+      default: break;
+    }
+    return sb.toString();
+  }
+
+  @Override
+  public final long xxHash64(final long offsetBytes, final long lengthBytes, final long seed) {
+    checkValid();
+    return XxHash64.hash(getUnsafeObject(), getCumulativeOffset(0) + offsetBytes, lengthBytes, seed);
+  }
+
+  @Override
+  public final long xxHash64(final long in, final long seed) {
+    return XxHash64.hash(in, seed);
+  }
+
+}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/UnsafeUtil.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/UnsafeUtil.java
index 0a99211..aabbb90 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/UnsafeUtil.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/UnsafeUtil.java
@@ -139,14 +139,14 @@
     } catch (final NumberFormatException | ArrayIndexOutOfBoundsException  e) {
       throw new IllegalArgumentException("Improper Java -version string: " + jdkVer + "\n" + e);
     }
-    //checkJavaVersion(jdkVer, p0, p1); //TODO Optional to omit this.
+    checkJavaVersion(jdkVer, p0, p1);
     return new int[] {p0, p1};
   }
 
   public static void checkJavaVersion(final String jdkVer, final int p0, final int p1) {
     if ( (p0 < 1) || ((p0 == 1) && (p1 < 8)) || (p0 > 13)  ) {
       throw new IllegalArgumentException(
-          "Unsupported JDK Major Version, must be one of 1.8, 8, 9, 10, 11, 12, 13: " + jdkVer);
+          "Unsupported JDK Major Version, must be one of 1.8, 8, 11, 17: " + jdkVer);
     }
   }
 
@@ -154,7 +154,7 @@
     try {
       return unsafe.objectFieldOffset(c.getDeclaredField(fieldName));
     } catch (final NoSuchFieldException e) {
-      throw new IllegalStateException(e);
+      throw new IllegalStateException(e + ": " + fieldName);
     }
   }
 
@@ -189,34 +189,4 @@
     }
   }
 
-  /**
-   * Assert the requested offset and length against the allocated size.
-   * The invariants equation is: {@code 0 <= reqOff <= reqLen <= reqOff + reqLen <= allocSize}.
-   * If this equation is violated and assertions are enabled, an {@link AssertionError} will
-   * be thrown.
-   * @param reqOff the requested offset
-   * @param reqLen the requested length
-   * @param allocSize the allocated size.
-   */
-  public static void assertBounds(final long reqOff, final long reqLen, final long allocSize) {
-    assert ((reqOff | reqLen | (reqOff + reqLen) | (allocSize - (reqOff + reqLen))) >= 0) :
-      "reqOffset: " + reqOff + ", reqLength: " + reqLen
-      + ", (reqOff + reqLen): " + (reqOff + reqLen) + ", allocSize: " + allocSize;
-  }
-
-  /**
-   * Check the requested offset and length against the allocated size.
-   * The invariants equation is: {@code 0 <= reqOff <= reqLen <= reqOff + reqLen <= allocSize}.
-   * If this equation is violated an {@link IllegalArgumentException} will be thrown.
-   * @param reqOff the requested offset
-   * @param reqLen the requested length
-   * @param allocSize the allocated size.
-   */
-  public static void checkBounds(final long reqOff, final long reqLen, final long allocSize) {
-    if ((reqOff | reqLen | (reqOff + reqLen) | (allocSize - (reqOff + reqLen))) < 0) {
-      throw new IllegalArgumentException(
-          "reqOffset: " + reqOff + ", reqLength: " + reqLen
-              + ", (reqOff + reqLen): " + (reqOff + reqLen) + ", allocSize: " + allocSize);
-    }
-  }
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/Utf8.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/Utf8.java
index d8fb52d..aee5eaf 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/Utf8.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/Utf8.java
@@ -67,7 +67,6 @@
     //Decode Direct CharBuffers and all other Appendables
 
     final long address = cumBaseOffset + offsetBytes;
-
     // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
     // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
     // Need to keep this loop int-indexed, because it's faster for Hotspot JIT, it doesn't insert
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/Util.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/Util.java
index 7660dca..d60a67d 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/Util.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/Util.java
@@ -36,16 +36,11 @@
  * @author Lee Rhodes
  */
 public final class Util {
+
+  private Util() { }
+
   public static final String LS = System.getProperty("line.separator");
 
-  //Byte Order related
-  public static final ByteOrder NON_NATIVE_BYTE_ORDER = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN
-      ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
-
-  public static ByteOrder otherByteOrder(final ByteOrder order) {
-    return (order == ByteOrder.nativeOrder()) ? NON_NATIVE_BYTE_ORDER : ByteOrder.nativeOrder();
-  }
-
   /**
    * Don't use sun.misc.Unsafe#copyMemory to copy blocks of memory larger than this
    * threshold, because internally it doesn't have safepoint polls, that may cause long
@@ -58,9 +53,15 @@
    */
   public static final int UNSAFE_COPY_THRESHOLD_BYTES = 1024 * 1024;
 
-  private Util() { }
+  //Byte Order related
+  public static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder();
 
-  //Byte Order Related
+  public static final ByteOrder NON_NATIVE_BYTE_ORDER = NATIVE_BYTE_ORDER == ByteOrder.LITTLE_ENDIAN
+      ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
+
+  public static ByteOrder otherByteOrder(final ByteOrder order) {
+    return (order == NATIVE_BYTE_ORDER) ? NON_NATIVE_BYTE_ORDER : NATIVE_BYTE_ORDER;
+  }
 
   /**
    * Returns true if the given byteOrder is the same as the native byte order.
@@ -91,7 +92,7 @@
    */
   public static long binarySearchLongs(final Memory mem, final long fromLongIndex,
       final long toLongIndex, final long key) {
-    UnsafeUtil.checkBounds(fromLongIndex << 3, (toLongIndex - fromLongIndex) << 3, mem.getCapacity());
+    ResourceImpl.checkBounds(fromLongIndex << 3, (toLongIndex - fromLongIndex) << 3, mem.getCapacity());
     long low = fromLongIndex;
     long high = toLongIndex - 1L;
 
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/VirtualMachineMemory.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/VirtualMachineMemory.java
index c4497e9..8395291 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/VirtualMachineMemory.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/VirtualMachineMemory.java
@@ -25,50 +25,32 @@
 /**
  * Extracts a version-dependent reference to the `sun.misc.VM` into a standalone
  * class. The package name for VM has changed in later versions. The appropriate
- * class will be loaded by the class loader depending on the Java version that
- * is used.
+ * class will be loaded by the class loader depending on the Java version that is used.
  * For more information, see: https://openjdk.java.net/jeps/238
  */
 public final class VirtualMachineMemory {
 
-    private static final Class<?> VM_CLASS;
-    private static final Method VM_MAX_DIRECT_MEMORY_METHOD;
-    private static final Method VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD;
-    private static final long maxDBBMemory;
-    private static final boolean isPageAligned;
+  private static final Class<?> VM_CLASS;
+  private static final Method VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD;
+  private static final boolean isPageAligned;
 
-    static {
-        try {
-            VM_CLASS = Class.forName("sun.misc.VM");
-            VM_MAX_DIRECT_MEMORY_METHOD = VM_CLASS.getDeclaredMethod("maxDirectMemory");
-            VM_MAX_DIRECT_MEMORY_METHOD.setAccessible(true);
-            maxDBBMemory = (long) VM_MAX_DIRECT_MEMORY_METHOD.invoke(null); // static method
-
-            VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD = VM_CLASS.getDeclaredMethod("isDirectMemoryPageAligned");
-            VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD.setAccessible(true);
-            isPageAligned = (boolean) VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD.invoke(null); // static method
-        } catch (final ClassNotFoundException | NoSuchMethodException |  IllegalAccessException
-                | IllegalArgumentException | InvocationTargetException | SecurityException e) {
-            throw new RuntimeException("Could not acquire sun.misc.VM class: " + e.getClass());
-        }
+  static {
+    try {
+      VM_CLASS = Class.forName("sun.misc.VM");
+      VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD = VM_CLASS.getDeclaredMethod("isDirectMemoryPageAligned");
+      VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD.setAccessible(true);
+      isPageAligned = (boolean) VM_IS_DIRECT_MEMORY_PAGE_ALIGNED_METHOD.invoke(null); // static method
+    } catch (final ClassNotFoundException | NoSuchMethodException |  IllegalAccessException
+        | IllegalArgumentException | InvocationTargetException | SecurityException e) {
+      throw new RuntimeException("Could not acquire sun.misc.VM class: " + e.getClass());
     }
+  }
 
-    /**
-     * Returns the maximum amount of allocatable direct buffer memory. The
-     * directMemory variable is initialized during system initialization.
-     *
-     * @return the maximum amount of allocatable direct buffer memory.
-     */
-    public static long getMaxDBBMemory() {
-        return maxDBBMemory;
-    }
-
-    /**
-     * Returns true if the direct buffers should be page aligned.
-     *
-     * @return flag that determines whether direct buffers should be page aligned.
-     */
-    public static boolean getIsPageAligned() {
-        return isPageAligned;
-    }
+  /**
+   * Returns true if the direct buffers should be page aligned.
+   * @return flag that determines whether direct buffers should be page aligned.
+   */
+  public static boolean getIsPageAligned() {
+    return isPageAligned;
+  }
 }
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/WritableDirectHandleImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/WritableDirectHandleImpl.java
deleted file mode 100644
index 76882ca..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/WritableDirectHandleImpl.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-import org.apache.datasketches.memory.Handle;
-import org.apache.datasketches.memory.Memory;
-import org.apache.datasketches.memory.WritableHandle;
-import org.apache.datasketches.memory.WritableMemory;
-
-/**
- * A Handle for a writable direct memory resource.
- * Joins an AutoCloseable WritableHandle with a WritableMemory and AllocateDirect resource.
- * Please read Javadocs for {@link Handle}.
- *
- * @author Lee Rhodes
- * @author Roman Leventov
- */
-public final class WritableDirectHandleImpl implements WritableHandle {
-
-  /**
-   * Having at least one final field makes this class safe for concurrent publication.
-   */
-  final AllocateDirect direct;
-  private BaseWritableMemoryImpl wMem;
-
-  WritableDirectHandleImpl(final AllocateDirect allocatedDirect, final BaseWritableMemoryImpl wMem) {
-    direct = allocatedDirect;
-    this.wMem = wMem;
-  }
-
-  @Override
-  public Memory get() {
-    return wMem;
-  }
-
-  @Override
-  public WritableMemory getWritable() {
-    return wMem;
-  }
-
-  //AutoCloseable
-
-  @Override
-  public void close() {
-    if (direct.doClose()) {
-      wMem = null;
-    }
-
-  }
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/WritableMapHandleImpl.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/WritableMapHandleImpl.java
deleted file mode 100644
index 7683bf7..0000000
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/WritableMapHandleImpl.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-import org.apache.datasketches.memory.Handle;
-import org.apache.datasketches.memory.WritableMapHandle;
-import org.apache.datasketches.memory.WritableMemory;
-
-/**
- * A Handle for a memory-mapped, writable file resource.
- * Joins a WritableHandle with an AutoCloseable WritableMap resource
- * Please read Javadocs for {@link Handle}.
- *
- * @author Roman Leventov
- * @author Lee Rhodes
- */
-public final class WritableMapHandleImpl extends MapHandleImpl
-    implements WritableMapHandle {
-
-  WritableMapHandleImpl(
-      final AllocateDirectWritableMap dirWmap,
-      final BaseWritableMemoryImpl wMem) {
-    super(dirWmap, wMem);
-  }
-
-  @Override
-  public WritableMemory getWritable() {
-    return wMem;
-  }
-
-  @Override
-  public void force() {
-    ((AllocateDirectWritableMap)dirMap).force();
-  }
-}
diff --git a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/package-info.java b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/package-info.java
index 4dd76ca..497fec0 100644
--- a/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/package-info.java
+++ b/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/package-info.java
@@ -19,7 +19,7 @@
 
 /**
  * <p>This package provides high performance primitive and primitive array access to direct (native),
- * off-heap memory and memory-mapped file resources, and consistent views into
+ * off-heap memory and memory-mapped file resources, consistent views into
  * {@link java.nio.ByteBuffer}, and on-heap primitive arrays. It can be used as a more
  * comprehensive and flexible replacement for {@link java.nio.ByteBuffer}.
  * </p>
@@ -60,7 +60,7 @@
  * </ul>
  *
  * <p>More specifically, this package provides access to four different types of resources using
- * two different access APIs. These resources are contiguous blobs of bytes that provide at least
+ * two different access APIs. These resources can be viewed as contiguous blobs of bytes that provide at least
  * byte-level read and write access. The four resources are:</p>
  *
  * <ul><li>Direct (a.k.a. Native) off-heap memory allocated by the user.</li>
@@ -82,72 +82,22 @@
  * <p>The resources don't know or care about the access APIs, and the access
  * APIs don't really know or care what resource they are accessing.</p>
  *
- * <p>An access API is joined with
- * a resource either with a static factory method or in combination with a
- * {@link org.apache.datasketches.memory.Handle}, which is used exclusively for resources that are
- * external to the JVM, such as allocation of direct memory and memory-mapped files.</p>
- *
- * <p>The role of a Handle is to hold onto the reference of a resource that is outside the control
- * of the JVM. The resource is obtained from the handle with {@code get()}.</p>
- *
- * <p>When a handle is extended for an AutoCloseable resource and then joined with an access API
- * it becomes an <i>implementation handle</i>. There are 3 implementation handles:</p>
- *
- * <ul><li>{@link org.apache.datasketches.memory.MapHandle}
- * for read-only access to a memory-mapped file</li>
- * <li>{@link org.apache.datasketches.memory.WritableMapHandle}
- * for writable access to a memory-mapped file</li>
- * <li>{@link org.apache.datasketches.memory.WritableHandle}
- * for writable access to off-heap memory.</li>
- * </ul>
- *
- * <p>As long as the implementation handle is valid the JVM will not attempt to close the resource.</p>
- *
- * <p>An implementation handle implements {@link java.lang.AutoCloseable},
- * which also enables compile-time checks for non-closed resources. If a Handle is acquired
- * in a try-with-resources (TWR) block, it's associated resource will be automatically closed by
- * the JVM at the end of the block.
- * The resource can also be explicitly closed by the user by calling {@code Handle.close()}.</p>
+ * <p>A Direct or memory-mapped file resource can also be explicitly closed by the user</p>
  * <blockquote><pre>
  *     //Using try-with-resources block:
- *     try (WritableyMapHandle handle = WritableMemory.map(File file)) {
- *       WritableMemory wMem = handle.get();
+ *     try (WritableMemory wmem = WritableMemory.map(File file)) {
  *       doWork(wMem) // read and write to memory mapped file.
  *     }
  *
  *     //Using explicit close():
- *     WritableMapHandle handle = WritableMemory.map(File file);
- *     WritableMemory wMem = handle.get();
+ *     WritableMemory wmem = WritableMemory.map(File file);
  *     doWork(wMem) // read and write to memory mapped file.
- *     handle.close();
+ *     wmem.close();
  * </pre></blockquote>
  *
- * <p>Where it is desirable to pass ownership of the resource (and the {@code close()}
- * responsibility) one can not use the TWR block. Instead:</p>
- * <blockquote><pre>
- *     WritableMapHandle handler = WritableMemory.map(File file);
- *     doWorkAndClose(handle); //passes the handle to object that closes the resource.
- * </pre></blockquote>
- *
- * <p>Whatever part of your process is responsible for allocating a resource external
- * to the JVM must be responsible for closing it or making sure it gets closed.
- * Since only the implementation Handles implement AutoCloseable, you must not let go of the
- * handle reference until you are done with its associated resource.</p>
- *
- * <p>As mentioned above, there are two ways to do this:</p>
- * <ul><li>Use a try-with-resources block.  At the end of the block, the JVM will automatically
- * close the resource.</li>
- *
- * <li>If you need to pass an external resource, pass the implementation resource handle, not the
- * access API. This means you are also passing the responsibility to close the resource.
- * If you have different parts of your code holding references to the same handle,
- * whichever one closes it first will make all the other resources invalid, so be careful.
- * As long as there is at least one reference to the handle that is still valid and the resource
- * has not been closed, the resource will remain valid. If you drop all references to all handles,
- * the JVM will eventually close the resource, making it invalid, but it is possible that you might
- * run out of memory first. Depending on this is a bad idea and a could be a serious,
- * hard-to-find bug.</li>
- * </ul>
+ * <p>Whatever thread of your process is responsible for allocating a direct or memory-mapped resource
+ * must be responsible for closing it or making sure it gets closed. This is also true for the special
+ * memory-mapping methods load(), isLoaded() and force().</p>
  *
  *<p>Moving back and forth between <i>Memory</i> and <i>Buffer</i>:</p>
  *<blockquote><pre>
@@ -162,11 +112,12 @@
  * <blockquote><pre>
  *     WritableMemory wMem = ...
  *     WritableMemory wReg = wMem.writableRegion(offset, length); //OR
- *     Memory reg = wMem.region(offset, length);
+ *     Memory region = wMem.region(offset, length);
  * </pre></blockquote>
  *
- * <p>With asserts enabled in the JVM, all methods are checked for bounds and
- * use-after-close violations.</p>
+ * <p>All methods are checked for bounds violations.</p>
+ *
+ * <p>The classes in this package are not thread-safe.</p>
  *
  * @author Lee Rhodes
  */
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java
index 4911e7d..423e59a 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java
@@ -23,134 +23,110 @@
 
 package org.apache.datasketches.memory.internal;
 
-import static org.apache.datasketches.memory.internal.Util.*;
+import static org.apache.datasketches.memory.internal.Util.getResourceFile;
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
 import java.io.File;
 import java.nio.ByteOrder;
 
-import org.apache.datasketches.memory.MapHandle;
 import org.apache.datasketches.memory.Memory;
-import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 public class AllocateDirectMapMemoryTest {
   private static final String LS = System.getProperty("line.separator");
-  MapHandle hand = null;
 
   @BeforeClass
   public void setReadOnly() {
     UtilTest.setGettysburgAddressFileToReadOnly();
   }
 
-  @Test
-  public void simpleMap() throws Exception {
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void simpleMap() {
     File file = getResourceFile("GettysburgAddress.txt");
-    assertTrue(AllocateDirectMap.isFileReadOnly(file));
-    try (MapHandle rh = Memory.map(file)) {
-      rh.close();
+    assertTrue(AllocateDirectWritableMap.isFileReadOnly(file));
+    try (Memory mem = Memory.map(file)) {
+      mem.close(); //explicit close
+    } //The Try-With-Resources will throw if already closed
+  }
+
+  @Test
+  public void printGettysbergAddress()  {
+    File file = getResourceFile("GettysburgAddress.txt");
+    try (Memory mem = Memory.map(file))
+    {
+      println("Mem Cap:       " + mem.getCapacity());
+      println("Total Offset:  " + mem.getTotalOffset());
+      println("Cum Offset:    " + ((ResourceImpl)mem).getCumulativeOffset(0));
+      println("Total Offset: " + mem.getTotalOffset());
+      StringBuilder sb = new StringBuilder();
+      mem.getCharsFromUtf8(43, 176, sb);
+      println(sb.toString());
+
+      println("");
+      Memory mem2 = mem.region(43 + 76, 20);
+      println("Mem Cap:       " + mem2.getCapacity());
+      println("Offset:        " + mem.getTotalOffset());
+      println("Cum Offset:    " + ((ResourceImpl)mem2).getCumulativeOffset(0));
+      println("Total Offset: " + mem2.getTotalOffset());
+      StringBuilder sb2 = new StringBuilder();
+      mem2.getCharsFromUtf8(0, 12, sb2);
+      println(sb2.toString());
     }
   }
 
   @Test
-  public void testIllegalArguments() throws Exception {
+  public void testIllegalArguments() {
     File file = getResourceFile("GettysburgAddress.txt");
-    try (MapHandle rh = Memory.map(file, -1, Integer.MAX_VALUE, ByteOrder.nativeOrder())) {
-      fail("Failed: testIllegalArgumentException: Position was negative.");
+    try (Memory mem = Memory.map(file, -1, Integer.MAX_VALUE, ByteOrder.nativeOrder())) {
+      fail("Failed: Position was negative.");
     } catch (IllegalArgumentException e) {
       //ok
     }
 
-    try (MapHandle rh = Memory.map(file, 0, -1, ByteOrder.nativeOrder())) {
-      fail("Failed: testIllegalArgumentException: Size was negative.");
+    try (Memory mem = Memory.map(file, 0, -1, ByteOrder.nativeOrder())) {
+      fail("Failed: Size was negative.");
     } catch (IllegalArgumentException e) {
       //ok
     }
   }
 
-  @Test
-  public void testMapAndMultipleClose() throws Exception {
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void testAccessAfterClose() {
     File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
-    try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
-      Memory map = rh.get();
-      assertEquals(memCapacity, map.getCapacity());
-      rh.close();
-      rh.close();
-      map.getCapacity(); //throws assertion error
-    } catch (AssertionError e) {
-      //OK
-    }
+    try (Memory mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
+      assertEquals(memCapacity, mem.getCapacity());
+    } //normal close via TWR
+    Memory mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder());
+    mem.close(); //normal manual close
+    mem.getCapacity(); //isLoaded(); //already closed, invalid
+  }
+
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void testReadFailAfterClose()  {
+    File file = getResourceFile("GettysburgAddress.txt");
+    long memCapacity = file.length();
+    Memory mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder());
+    mem.close();
+    mem.isLoaded();
   }
 
   @Test
-  public void testReadFailAfterClose() throws Exception {
+  public void testLoad()  {
     File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
-    try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
-      Memory mmf = rh.get();
-      rh.close();
-      mmf.getByte(0);
-    } catch (AssertionError e) {
-      //OK
-    }
-  }
-
-  @Test
-  public void testLoad() throws Exception {
-    File file = getResourceFile("GettysburgAddress.txt");
-    long memCapacity = file.length();
-    try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
-      rh.load();
-      assertTrue(rh.isLoaded());
-      rh.close();
-    }
-  }
-
-  @Test
-  public void testHandlerHandoffWithTWR() throws Exception {
-    File file = getResourceFile("GettysburgAddress.txt");
-    long memCapacity = file.length();
-    Memory mem;
-    try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
-      rh.load();
-      assertTrue(rh.isLoaded());
-      hand = rh;
-      mem = rh.get();
-    } //TWR closes
-    assertFalse(mem.isValid());
-    //println(""+mem.isValid());
-  }
-
-  @Test
-  public void testHandoffWithoutClose() throws Exception {
-    File file = getResourceFile("GettysburgAddress.txt");
-    long memCapacity = file.length();
-    MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder());
-    rh.load();
-    assertTrue(rh.isLoaded());
-    hand = rh;
-    //The receiver of the handler must close the resource, in this case it is the class.
-  }
-
-  @AfterClass
-  public void afterAllTests() throws Exception {
-      if (hand != null) {
-      Memory mem = hand.get();
-      if ((mem != null) && mem.isValid()) {
-        hand.close();
-        assertFalse(mem.isValid());
-      }
-    }
+    try (Memory mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
+      mem.load();
+      assertTrue(mem.isLoaded());
+    } //normal TWR close
   }
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   static void println(final Object o) {
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java
index 7ebe3e5..c259fda 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java
@@ -21,48 +21,36 @@
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.fail;
+import static org.testng.Assert.assertTrue;
 
-import org.apache.datasketches.memory.BaseState;
 import org.apache.datasketches.memory.DefaultMemoryRequestServer;
 import org.apache.datasketches.memory.MemoryRequestServer;
-import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.Resource;
 import org.apache.datasketches.memory.WritableMemory;
-import org.testng.annotations.AfterClass;
 import org.testng.annotations.Test;
 
 public class AllocateDirectMemoryTest {
 
-  @Test
-  public void simpleAllocateDirect() throws Exception {
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void simpleAllocateDirect()  {
     int longs = 32;
-    WritableMemory wMem;
-    try (WritableHandle wh = WritableMemory.allocateDirect(longs << 3)) {
-      wMem = wh.getWritable();
-      for (int i = 0; i<longs; i++) {
+    try (WritableMemory wMem = WritableMemory.allocateDirect(longs << 3)) {
+      for (int i = 0; i < longs; i++) {
         wMem.putLong(i << 3, i);
         assertEquals(wMem.getLong(i << 3), i);
       }
       //inside the TWR block the memory should be valid
-      ((BaseStateImpl)wMem).checkValid();
-      //OK
-    }
-    //The TWR block has exited, so the memory should be invalid
-    try {
-      ((BaseStateImpl)wMem).checkValid();
-      fail();
-    } catch (final RuntimeException e) {
-      //OK
-    }
+      ((ResourceImpl)wMem).checkValid();
+      wMem.close(); //explicit close
+    } //normal TWR close will not throw if already closed
   }
 
   @Test
-  public void checkDefaultMemoryRequestServer() throws Exception {
+  public void checkDefaultMemoryRequestServer()  {
     int longs1 = 32;
     int bytes1 = longs1 << 3;
-    try (WritableHandle wh = WritableMemory.allocateDirect(bytes1)) {
-      WritableMemory origWmem = wh.getWritable();
-      for (int i = 0; i<longs1; i++) { //puts data in wMem1
+    try (WritableMemory origWmem = WritableMemory.allocateDirect(bytes1)) {
+      for (int i = 0; i < longs1; i++) { //puts data in wMem1
         origWmem.putLong(i << 3, i);
         assertEquals(origWmem.getLong(i << 3), i);
       }
@@ -71,13 +59,13 @@
       int longs2 = 64;
       int bytes2 = longs2 << 3;
       MemoryRequestServer memReqSvr;
-      if (BaseState.defaultMemReqSvr == null) {
+      if (Resource.defaultMemReqSvr == null) {
         memReqSvr = new DefaultMemoryRequestServer();
       } else {
         memReqSvr = origWmem.getMemoryRequestServer();
       }
       WritableMemory newWmem = memReqSvr.request(origWmem, bytes2);
-      assertFalse(newWmem.isDirect()); //on heap by default
+      assertFalse(newWmem.isDirectResource()); //on heap by default
       for (int i = 0; i < longs2; i++) {
           newWmem.putLong(i << 3, i);
           assertEquals(newWmem.getLong(i << 3), i);
@@ -89,36 +77,25 @@
   }
 
   @Test
-  public void checkNonNativeDirect() throws Exception {
-    try (WritableHandle h = WritableMemory.allocateDirect(128, Util.NON_NATIVE_BYTE_ORDER, null)) {
-      WritableMemory wmem = h.getWritable();
+  public void checkNonNativeDirect()  {
+    try (WritableMemory wmem = WritableMemory.allocateDirect(128, Util.NON_NATIVE_BYTE_ORDER, null)) {
       wmem.putChar(0, (char) 1);
       assertEquals(wmem.getByte(1), (byte) 1);
     }
   }
 
   @Test
-  public void checkExplicitClose() throws Exception {
+  public void checkExplicitClose() {
     final long cap = 128;
-    try (WritableHandle wdh = WritableMemory.allocateDirect(cap)) {
-      wdh.close(); //explicit close. Does the work of closing
-    } //end of scope call to Cleaner/Deallocator also will be redundant
-  }
-
-
-  @AfterClass
-  public void checkDirectCounter() {
-    WritableMemory.writableWrap(new byte[8]);
-    long count = BaseState.getCurrentDirectMemoryAllocations();
-    if (count != 0) {
-      println(""+count);
-      fail();
-    }
+    WritableMemory wMem = WritableMemory.allocateDirect(cap);
+    assertTrue(wMem.isValid());
+    wMem.close();
+    assertFalse(wMem.isValid());
   }
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java
index 9cecaaa..98d3c2a 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java
@@ -36,14 +36,9 @@
 import java.io.UnsupportedEncodingException;
 import java.nio.ByteOrder;
 
-import org.apache.datasketches.memory.BaseState;
-import org.apache.datasketches.memory.MapHandle;
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.ReadOnlyException;
-import org.apache.datasketches.memory.WritableHandle;
-import org.apache.datasketches.memory.WritableMapHandle;
 import org.apache.datasketches.memory.WritableMemory;
-import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -58,14 +53,13 @@
   @Test
   public void simpleMap() throws Exception {
     File file = getResourceFile("GettysburgAddress.txt");
-    try (MapHandle h = Memory.map(file); WritableMapHandle wh = (WritableMapHandle) h) {
-      Memory mem = h.get();
+    try (Memory mem = Memory.map(file)) {
       byte[] bytes = new byte[(int)mem.getCapacity()];
       mem.getByteArray(0, bytes, 0, bytes.length);
       String text = new String(bytes, UTF_8);
       println(text);
       try {
-        wh.force();
+        mem.force();
         fail();
       } catch (ReadOnlyException e) {
         //OK
@@ -87,17 +81,13 @@
       }
     }
     assertTrue(file.createNewFile());
-    assertTrue (file.setWritable(true, false)); //writable=true, ownerOnly=false
-    assertTrue (file.isFile());
+    assertTrue(file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue(file.isFile());
     file.deleteOnExit();  //comment out if you want to examine the file.
 
     try (
-        WritableMapHandle dstHandle
-          = WritableMemory.writableMap(file, 0, bytes, ByteOrder.nativeOrder());
-        WritableHandle srcHandle = WritableMemory.allocateDirect(bytes)) {
-
-      WritableMemory dstMem = dstHandle.getWritable();
-      WritableMemory srcMem = srcHandle.getWritable();
+        WritableMemory dstMem = WritableMemory.writableMap(file, 0, bytes, ByteOrder.nativeOrder());
+        WritableMemory srcMem = WritableMemory.allocateDirect(bytes)) {
 
       for (long i = 0; i < longs; i++) {
         srcMem.putLong(i << 3, i); //load source with consecutive longs
@@ -105,7 +95,7 @@
 
       srcMem.copyTo(0, dstMem, 0, srcMem.getCapacity()); //off-heap to off-heap copy
 
-      dstHandle.force(); //push any remaining to the file
+      dstMem.force(); //push any remaining to the file
 
       //check end value
       assertEquals(dstMem.getLong(longs - 1L << 3), longs - 1L);
@@ -128,8 +118,7 @@
     file.deleteOnExit();  //comment out if you want to examine the file.
 
     final long bytes = 8;
-    try (WritableMapHandle h = WritableMemory.writableMap(file, 0L, bytes, Util.NON_NATIVE_BYTE_ORDER)) {
-      WritableMemory wmem = h.getWritable();
+    try (WritableMemory wmem = WritableMemory.writableMap(file, 0L, bytes, Util.NON_NATIVE_BYTE_ORDER)) {
       wmem.putChar(0, (char) 1);
       assertEquals(wmem.getByte(1), (byte) 1);
     }
@@ -138,16 +127,15 @@
   @Test(expectedExceptions = RuntimeException.class)
   public void testMapException() throws IOException {
     File dummy = createFile("dummy.txt", ""); //zero length
-    //throws java.lang.reflect.InvocationTargetException
+    //throws IOException "Invalid Argument"
     Memory.map(dummy, 0, dummy.length(), ByteOrder.nativeOrder());
   }
 
   @Test(expectedExceptions = ReadOnlyException.class)
-  public void simpleMap2() throws Exception {
+  public void simpleMap2() throws IOException {
     File file = getResourceFile("GettysburgAddress.txt");
     assertTrue(file.canRead() && !file.canWrite());
-    try (WritableMapHandle rh =
-        WritableMemory.writableMap(file)) { //throws
+    try (WritableMemory wmem = WritableMemory.writableMap(file)) { //throws
       //
     }
   }
@@ -155,12 +143,7 @@
   @Test(expectedExceptions = ReadOnlyException.class)
   public void checkOverLength() throws Exception  {
     File file = getResourceFile("GettysburgAddress.txt");
-    try (WritableMapHandle rh =
-        WritableMemory.writableMap(file, 0, 1 << 20, ByteOrder.nativeOrder())) {
-      //
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
+    WritableMemory.writableMap(file, 0, 1 << 20, ByteOrder.nativeOrder());
   }
 
   @Test
@@ -173,10 +156,9 @@
     byte[] correctByteArr = correctStr.getBytes(UTF_8);
     long corrBytes = correctByteArr.length;
 
-    try (MapHandle rh = Memory.map(origFile, 0, origBytes, ByteOrder.nativeOrder())) {
-      Memory map = rh.get();
-      rh.load();
-      assertTrue(rh.isLoaded());
+    try (Memory map = Memory.map(origFile, 0, origBytes, ByteOrder.nativeOrder())) {
+      map.load();
+      assertTrue(map.isLoaded());
       //confirm orig string
       byte[] buf = new byte[(int)origBytes];
       map.getByteArray(0, buf, 0, (int)origBytes);
@@ -184,14 +166,12 @@
       assertEquals(bufStr, origStr);
     }
 
-    try (WritableMapHandle wrh = WritableMemory.writableMap(origFile, 0, corrBytes,
-        ByteOrder.nativeOrder())) {
-      WritableMemory wMap = wrh.getWritable();
-      wrh.load();
-      assertTrue(wrh.isLoaded());
+    try (WritableMemory wMap = WritableMemory.writableMap(origFile, 0, corrBytes, ByteOrder.nativeOrder())) {
+      wMap.load();
+      assertTrue(wMap.isLoaded());
       // over write content
       wMap.putByteArray(0, correctByteArr, 0, (int)corrBytes);
-      wrh.force();
+      wMap.force();
       //confirm correct string
       byte[] buf = new byte[(int)corrBytes];
       wMap.getByteArray(0, buf, 0, (int)corrBytes);
@@ -215,25 +195,8 @@
   }
 
   @Test
-  public void checkExplicitClose() throws Exception {
-    File file = getResourceFile("GettysburgAddress.txt");
-    try (MapHandle wmh = Memory.map(file)) {
-      wmh.close(); //explicit close.
-    } //end of scope call to Cleaner/Deallocator also will be redundant
-  }
-
-  @AfterClass
-  public void checkDirectCounter() {
-    long count =  BaseState.getCurrentDirectMemoryMapAllocations();
-      if (count != 0) {
-        println(""+count);
-        fail();
-      }
-    }
-
-  @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   static void println(final Object o) {
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseBufferTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseBufferTest.java
index 4e8bfff..759fdd5 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseBufferTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseBufferTest.java
@@ -22,8 +22,8 @@
 import static org.testng.Assert.fail;
 
 import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.BufferPositionInvariantsException;
 import org.apache.datasketches.memory.Memory;
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
@@ -40,7 +40,7 @@
     try {
       buf.setStartPositionEnd(0, 0, 101);
       fail();
-    } catch (AssertionError e) {
+    } catch (BufferPositionInvariantsException e) {
       //ok
     }
   }
@@ -48,19 +48,19 @@
   @Test
   public void checkLimitsAndCheck() {
     Buffer buf = Memory.wrap(new byte[100]).asBuffer();
-    buf.setAndCheckStartPositionEnd(40, 45, 50);
-    buf.setAndCheckStartPositionEnd(0, 0, 100);
+    buf.setStartPositionEnd(40, 45, 50);
+    buf.setStartPositionEnd(0, 0, 100);
     try {
-      buf.setAndCheckStartPositionEnd(0, 0, 101);
+      buf.setStartPositionEnd(0, 0, 101);
       fail();
-    } catch (IllegalArgumentException e) {
+    } catch (BufferPositionInvariantsException e) {
       //ok
     }
-    buf.setAndCheckPosition(100);
+    buf.setPosition(100);
     try {
-      buf.setAndCheckPosition(101);
+      buf.setPosition(101);
       fail();
-    } catch (IllegalArgumentException e) {
+    } catch (BufferPositionInvariantsException e) {
       //ok
     }
     buf.setPosition(99);
@@ -68,22 +68,19 @@
     try {
       buf.incrementAndCheckPosition(1L);
       fail();
-    } catch (IllegalArgumentException e) {
+    } catch (BufferPositionInvariantsException e) {
       //ok
     }
   }
 
-  @Test
-  public void checkCheckValid() throws Exception {
-    WritableMemory wmem;
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void checkCheckValid() {
+
     Buffer buf;
-    try (WritableHandle hand = WritableMemory.allocateDirect(100)) {
-      wmem = hand.getWritable();
+    try (WritableMemory wmem = WritableMemory.allocateDirect(100)) {
       buf = wmem.asBuffer();
     }
-    try {
-      @SuppressWarnings("unused")
-      Memory mem = buf.asMemory();
-    } catch (AssertionError ae) { }
+    @SuppressWarnings("unused")
+    Memory mem = buf.asMemory(); //wmem, buf no longer valid
   }
 }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Buffer2Test.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Buffer2Test.java
index e625cb4..d40ce05 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Buffer2Test.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Buffer2Test.java
@@ -38,7 +38,7 @@
 public class Buffer2Test {
 
   @Test
-  public void testWrapByteBuf() {
+  public void testWrapHeapByteBuf() {
     ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
 
     Byte b = 0;
@@ -50,11 +50,13 @@
 
     Buffer buffer = Buffer.wrap(bb.asReadOnlyBuffer().order(ByteOrder.nativeOrder()));
     while (buffer.hasRemaining()) {
-      assertEquals(bb.get(), buffer.getByte());
+      byte a1 = bb.get();
+      byte b1 = buffer.getByte();
+      assertEquals(a1, b1);
     }
 
-    assertEquals(true, buffer.hasArray());
-    assertEquals(true, buffer.hasByteBuffer());
+    assertEquals(true, buffer.isHeapResource());
+    assertEquals(true, buffer.isByteBufferResource());
   }
 
   @Test
@@ -73,8 +75,8 @@
       assertEquals(bb.get(), buffer.getByte());
     }
 
-    assertEquals(false, buffer.hasArray());
-    assertEquals(true, buffer.hasByteBuffer());
+    assertEquals(false, buffer.isHeapResource());
+    assertEquals(true, buffer.isByteBufferResource());
   }
 
   @Test
@@ -96,8 +98,8 @@
     buffer.getByteArray(copyByteArray, 0, 64);
     assertEquals(byteArray, copyByteArray);
 
-    assertEquals(true, buffer.hasArray());
-    assertEquals(false, buffer.hasByteBuffer());
+    assertEquals(true, buffer.isHeapResource());
+    assertEquals(false, buffer.isByteBufferResource());
   }
 
   @Test
@@ -328,7 +330,7 @@
     }
     bb.position(10);
 
-    Buffer buffer = Buffer.wrap(bb.slice().order(ByteOrder.nativeOrder())); //slice = 54
+    Buffer buffer = Buffer.wrap(bb.slice().order(ByteOrder.nativeOrder())); //slice size = 54
     buffer.setPosition(30);//remaining = 24
     Buffer dupBuffer = buffer.duplicate(); //all 54
     Buffer regionBuffer = buffer.region(); //24
@@ -351,7 +353,7 @@
     for (int i = 0; i < n; i++) { arr[i] = i; }
     Memory mem = Memory.wrap(arr);
     Buffer buf = mem.asBuffer();
-    Buffer reg = buf.region(n2 * 8, n2 * 8, buf.getTypeByteOrder()); //top half
+    Buffer reg = buf.region(n2 * 8, n2 * 8, buf.getByteOrder()); //top half
     for (int i = 0; i < n2; i++) {
       long v = reg.getLong(i * 8);
       long e = i + n2;
@@ -375,12 +377,12 @@
 
     assertEquals(buffer.getCapacity(), memory.getCapacity());
 
-    while(buffer.hasRemaining()){
+    while (buffer.hasRemaining()) {
       assertEquals(memory.getByte(buffer.getPosition()), buffer.getByte());
     }
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testROByteBuffer() {
     byte[] arr = new byte[64];
     ByteBuffer roBB = ByteBuffer.wrap(arr).asReadOnlyBuffer();
@@ -449,7 +451,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java
index 535b0ca..ac90665 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java
@@ -19,6 +19,7 @@
 
 package org.apache.datasketches.memory.internal;
 
+import org.apache.datasketches.memory.MemoryBoundsException;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
@@ -26,212 +27,84 @@
 
   private final WritableMemory writableMemory = WritableMemory.allocate(8);
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetBoolean() {
-    writableMemory.getBoolean(7);
-    try {
-      writableMemory.getBoolean(8);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.getBoolean(8);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutBoolean() {
-    writableMemory.putBoolean(7, true);
-    try {
-      writableMemory.putBoolean(8, true);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.putBoolean(8, true);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetByte() {
-    writableMemory.getByte(7);
-    try {
-      writableMemory.getByte(8);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.getByte(8);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutByte() {
-    writableMemory.putByte(7, (byte) 1);
-    try {
-      writableMemory.putByte(8, (byte) 1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.putByte(8, (byte) 1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetChar() {
-    writableMemory.getChar(6);
-    try {
-      writableMemory.getChar(7);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.getChar(7);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutChar() {
-    writableMemory.putChar(6, 'a');
-    try {
-      writableMemory.putChar(7, 'a');
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.putChar(7, 'a');
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetShort() {
-    writableMemory.getShort(6);
-    try {
-      writableMemory.getShort(7);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.getShort(7);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutShort() {
-    writableMemory.putShort(6, (short) 1);
-    try {
-      writableMemory.putShort(7, (short) 1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.putShort(7, (short) 1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetInt() {
-    writableMemory.getInt(4);
-    try {
-      writableMemory.getInt(5);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.getInt(5);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutInt() {
-    writableMemory.putInt(4, 1);
-    try {
-      writableMemory.putInt(5, 1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.putInt(5, 1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetFloat() {
-    writableMemory.getFloat(4);
-    try {
-      writableMemory.getFloat(5);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.getFloat(5);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutFloat() {
-    writableMemory.putFloat(4, 1f);
-    try {
-      writableMemory.putFloat(5, 1f);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.putFloat(5, 1f);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetLong() {
-    writableMemory.getLong(0);
-    try {
-      writableMemory.getLong(1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.getLong(1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutLong() {
-    writableMemory.putLong(0, 1L);
-    try {
-      writableMemory.putLong(1, 1L);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.putLong(1, 1L);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetDouble() {
-    writableMemory.getDouble(0);
-    try {
-      writableMemory.getDouble(1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.getDouble(1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutDouble() {
-    writableMemory.putDouble(0, 1d);
-    try {
-      writableMemory.putDouble(1, 1d);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableMemory.putDouble(1, 1d);
   }
 
-  @Test
-  public void testGetAndAddLong() {
-    writableMemory.getAndAddLong(0, 1L);
-    try {
-      writableMemory.getAndAddLong(1, 1L);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
-  }
-
-  @Test
-  public void testGetAndSetLong() {
-    writableMemory.getAndSetLong(0, 1L);
-    try {
-      writableMemory.getAndSetLong(1, 1L);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
-  }
-
-  @Test
-  public void testCompareAndSwapLong() {
-    writableMemory.compareAndSwapLong(0, 0L, 1L);
-    try {
-      writableMemory.compareAndSwapLong(1, 0L, 1L);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
-  }
 }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferInvariantsTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferInvariantsTest.java
index 735c6b0..acc7f79 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferInvariantsTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferInvariantsTest.java
@@ -25,8 +25,8 @@
 import java.nio.ByteBuffer;
 
 import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.BufferPositionInvariantsException;
 import org.apache.datasketches.memory.WritableBuffer;
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
@@ -161,15 +161,14 @@
 
   @Test
   public void checkLimitsDirect() throws Exception {
-    try (WritableHandle hand = WritableMemory.allocateDirect(100)) {
-      WritableMemory wmem = hand.getWritable();
+    try (WritableMemory wmem = WritableMemory.allocateDirect(100)) {
       Buffer buf = wmem.asBuffer();
       buf.setStartPositionEnd(40, 45, 50);
       buf.setStartPositionEnd(0, 0, 100);
       try {
         buf.setStartPositionEnd(0, 0, 101);
         fail();
-      } catch (AssertionError e) {
+      } catch (BufferPositionInvariantsException e) {
         //ok
       }
     }
@@ -232,8 +231,7 @@
   @Test
   public void testBufDirect() throws Exception {
     int n = 25;
-    try (WritableHandle whand = WritableMemory.allocateDirect(n)) {
-    WritableMemory wmem = whand.getWritable();
+    try (WritableMemory wmem = WritableMemory.allocateDirect(n)) {
     WritableBuffer buf = wmem.asWritableBuffer();
     for (byte i = 0; i < n; i++) { buf.putByte(i); }
     buf.setPosition(0);
@@ -302,14 +300,13 @@
 //    printbuf(reg);
   }
 
-
   static void printbb(ByteBuffer bb) {
     println("pos: " + bb.position() + ", lim: " + bb.limit() + ", cap: " + bb.capacity());
     int rem = bb.remaining();
     int pos = bb.position();
     int i;
-    for (i = 0; i < (rem-1); i++) {
-      print(bb.get(i+ pos) + ", ");
+    for (i = 0; i < (rem - 1); i++) {
+      print(bb.get(i + pos) + ", ");
     }
     println(bb.get(i + pos) + "\n");
   }
@@ -319,8 +316,8 @@
     long rem = buf.getRemaining();
     long pos = buf.getPosition();
     int i;
-    for (i = 0; i < (rem-1); i++) {
-      print(buf.getByte(i+ pos) + ", ");
+    for (i = 0; i < (rem - 1); i++) {
+      print(buf.getByte(i + pos) + ", ");
     }
     println(buf.getByte(i + pos) + "\n");
   }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java
index 6f9f62a..73a9da2 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java
@@ -33,82 +33,82 @@
 
   private final WritableBuffer buf = (WritableBuffer) Buffer.wrap(ByteBuffer.allocate(8));
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutByte() {
     buf.putByte(0, (byte) 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutBytePositional() {
     buf.putByte((byte) 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutBoolean() {
     buf.putBoolean(0, true);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutBooleanPositional() {
     buf.putBoolean(true);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutShort() {
     buf.putShort(0, (short) 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutShortPositional() {
     buf.putShort((short) 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutChar() {
     buf.putChar(0, (char) 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutCharPositional() {
     buf.putChar((char) 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutInt() {
     buf.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutIntPositional() {
     buf.putInt(1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutLong() {
     buf.putLong(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutLongPositional() {
     buf.putLong(1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutFloat() {
     buf.putFloat(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutFloatPositional() {
     buf.putFloat(1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutDouble() {
     buf.putDouble(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutDoublePositional() {
     buf.putDouble(1);
   }
@@ -155,19 +155,19 @@
 
   // Now, test that various ways to obtain a read-only buffer produce a read-only buffer indeed
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testWritableMemoryAsBuffer() {
     WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asBuffer();
     buf1.putInt(1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testWritableBufferRegion() {
     WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asWritableBuffer().region();
     buf1.putInt(1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testWritableBufferDuplicate() {
     WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asWritableBuffer().duplicate();
     buf1.putInt(1);
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java
index 64b3c77..529eb5e 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java
@@ -25,8 +25,8 @@
 import java.nio.ByteOrder;
 import java.util.List;
 
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.BufferPositionInvariantsException;
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableBuffer;
 import org.apache.datasketches.memory.WritableMemory;
@@ -38,8 +38,7 @@
   @Test
   public void checkDirectRoundTrip() throws Exception {
     int n = 1024; //longs
-    try (WritableHandle wh = WritableMemory.allocateDirect(n * 8)) {
-      WritableMemory wmem = wh.getWritable();
+    try (WritableMemory wmem = WritableMemory.allocateDirect(n * 8)) {
       WritableBuffer wbuf = wmem.asWritableBuffer();
       for (int i = 0; i < n; i++) {
         wbuf.putLong(i);
@@ -203,7 +202,7 @@
     ByteBuffer bb = ByteBuffer.allocate(n * 8);
     bb.order(ByteOrder.BIG_ENDIAN);
     Buffer buf = Buffer.wrap(bb);
-    assertEquals(buf.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(buf.getByteOrder(), ByteOrder.BIG_ENDIAN);
   }
 
   @Test
@@ -262,58 +261,54 @@
     int n = 16;
     int n2 = n / 2;
     long[] arr = new long[n];
-    for (int i = 0; i < n; i++) { arr[i] = i; }
-    WritableBuffer wbuf = WritableMemory.writableWrap(arr).asWritableBuffer();
+    for (int i = 0; i < n; i++) { arr[i] = i; } //0...n-1
+    WritableMemory mem = WritableMemory.writableWrap(arr);
+    WritableBuffer wbuf = mem.asWritableBuffer();
     for (int i = 0; i < n; i++) {
-      assertEquals(wbuf.getLong(), i); //write all
-      //println("" + wmem.getLong(i * 8));
+      assertEquals(wbuf.getLong(), i); //0...n-1
+      println("" + wbuf.getLong(i * 8));
     }
-    //println("");
+    println("");
     wbuf.setPosition(n2 * 8);
     WritableBuffer reg = wbuf.writableRegion();
     for (int i = 0; i < n2; i++) { reg.putLong(i); } //rewrite top half
     wbuf.resetPosition();
     for (int i = 0; i < n; i++) {
+      println("" + wbuf.getLong(i * 8));
       assertEquals(wbuf.getLong(), i % 8);
-      //println("" + wmem.getLong(i * 8));
     }
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = IllegalStateException.class)
   public void checkParentUseAfterFree() throws Exception {
     int bytes = 64 * 8;
-    WritableHandle wh = WritableMemory.allocateDirect(bytes);
-    WritableMemory wmem = wh.getWritable();
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes);
     WritableBuffer wbuf = wmem.asWritableBuffer();
-    wh.close();
-    //with -ea assert: Memory not valid.
-    //with -da sometimes segfaults, sometimes passes!
+    wmem.close();
     wbuf.getLong();
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = IllegalStateException.class)
   public void checkRegionUseAfterFree() throws Exception {
     int bytes = 64;
-    WritableHandle wh = WritableMemory.allocateDirect(bytes);
-    Memory wmem = wh.get();
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes);
 
     Buffer reg = wmem.asBuffer().region();
-    wh.close();
+    wmem.close();
     //with -ea assert: Memory not valid.
     //with -da sometimes segfaults, sometimes passes!
     reg.getByte();
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = BufferPositionInvariantsException.class)
   public void checkBaseBufferInvariants() {
     WritableBuffer wbuf = WritableMemory.allocate(64).asWritableBuffer();
     wbuf.setStartPositionEnd(1, 0, 2); //out of order
   }
 
-
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonBufferTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonBufferTest.java
index e5033a2..3cbe87d 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonBufferTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonBufferTest.java
@@ -21,7 +21,6 @@
 
 import static org.testng.Assert.assertEquals;
 
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.WritableBuffer;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
@@ -31,8 +30,7 @@
   @Test
   public void checkSetGet() throws Exception {
     int memCapacity = 60; //must be at least 60
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       WritableBuffer buf = mem.asWritableBuffer();
       assertEquals(buf.getCapacity(), memCapacity);
       setGetTests(buf);
@@ -133,8 +131,7 @@
   @Test
   public void checkSetGetArrays() throws Exception {
     int memCapacity = 32;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       WritableBuffer buf = mem.asWritableBuffer();
       assertEquals(buf.getCapacity(), memCapacity);
       setGetArraysTests(buf);
@@ -152,7 +149,7 @@
     buf.putBooleanArray(srcArray1, 0, words);
     buf.resetPosition();
     buf.getBooleanArray(dstArray1, 0, words);
-    for (int i=0; i<words; i++) {
+    for (int i = 0; i < words; i++) {
       assertEquals(dstArray1[i], srcArray1[i]);
     }
 
@@ -162,7 +159,7 @@
     buf.putByteArray(srcArray2, 0, words);
     buf.resetPosition();
     buf.getByteArray(dstArray2, 0, words);
-    for (int i=0; i<words; i++) {
+    for (int i = 0; i < words; i++) {
       assertEquals(dstArray2[i], srcArray2[i]);
     }
 
@@ -172,7 +169,7 @@
     buf.putCharArray(srcArray3, 0, words);
     buf.resetPosition();
     buf.getCharArray(dstArray3, 0, words);
-    for (int i=0; i<words; i++) {
+    for (int i = 0; i < words; i++) {
       assertEquals(dstArray3[i], srcArray3[i]);
     }
 
@@ -182,7 +179,7 @@
     buf.putDoubleArray(srcArray4, 0, words);
     buf.resetPosition();
     buf.getDoubleArray(dstArray4, 0, words);
-    for (int i=0; i<words; i++) {
+    for (int i = 0; i < words; i++) {
       assertEquals(dstArray4[i], srcArray4[i], 0.0);
     }
 
@@ -192,7 +189,7 @@
     buf.putFloatArray(srcArray5, 0, words);
     buf.resetPosition();
     buf.getFloatArray(dstArray5, 0, words);
-    for (int i=0; i<words; i++) {
+    for (int i = 0; i < words; i++) {
       assertEquals(dstArray5[i], srcArray5[i], 0.0);
     }
 
@@ -202,7 +199,7 @@
     buf.putIntArray(srcArray6, 0, words);
     buf.resetPosition();
     buf.getIntArray(dstArray6, 0, words);
-    for (int i=0; i<words; i++) {
+    for (int i = 0; i < words; i++) {
       assertEquals(dstArray6[i], srcArray6[i]);
     }
 
@@ -212,7 +209,7 @@
     buf.putLongArray(srcArray7, 0, words);
     buf.resetPosition();
     buf.getLongArray(dstArray7, 0, words);
-    for (int i=0; i<words; i++) {
+    for (int i = 0; i < words; i++) {
       assertEquals(dstArray7[i], srcArray7[i]);
     }
 
@@ -222,7 +219,7 @@
     buf.putShortArray(srcArray8, 0, words);
     buf.resetPosition();
     buf.getShortArray(dstArray8, 0, words);
-    for (int i=0; i<words; i++) {
+    for (int i = 0; i < words; i++) {
       assertEquals(dstArray8[i], srcArray8[i]);
     }
   }
@@ -230,8 +227,7 @@
   @Test
   public void checkSetGetPartialArraysWithOffset() throws Exception {
     int memCapacity = 32;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       WritableBuffer buf = mem.asWritableBuffer();
       assertEquals(buf.getCapacity(), memCapacity);
       setGetPartialArraysWithOffsetTests(buf);
@@ -239,84 +235,84 @@
   }
 
   public static void setGetPartialArraysWithOffsetTests(WritableBuffer buf) {
-    int items= 4;
+    int items = 4;
     boolean[] srcArray1 = {true, false, true, false};
     boolean[] dstArray1 = new boolean[items];
     buf.resetPosition();
-    buf.putBooleanArray(srcArray1, 2, items/2);
+    buf.putBooleanArray(srcArray1, 2, items / 2);
     buf.resetPosition();
-    buf.getBooleanArray(dstArray1, 2, items/2);
-    for (int i=2; i<items; i++) {
+    buf.getBooleanArray(dstArray1, 2, items / 2);
+    for (int i = 2; i < items; i++) {
       assertEquals(dstArray1[i], srcArray1[i]);
     }
 
     byte[] srcArray2 = { 1, -2, 3, -4 };
     byte[] dstArray2 = new byte[items];
     buf.resetPosition();
-    buf.putByteArray(srcArray2, 2, items/2);
+    buf.putByteArray(srcArray2, 2, items / 2);
     buf.resetPosition();
-    buf.getByteArray(dstArray2, 2, items/2);
-    for (int i=2; i<items; i++) {
+    buf.getByteArray(dstArray2, 2, items / 2);
+    for (int i = 2; i < items; i++) {
       assertEquals(dstArray2[i], srcArray2[i]);
     }
 
     char[] srcArray3 = { 'A', 'B', 'C', 'D' };
     char[] dstArray3 = new char[items];
     buf.resetPosition();
-    buf.putCharArray(srcArray3, 2, items/2);
+    buf.putCharArray(srcArray3, 2, items / 2);
     buf.resetPosition();
-    buf.getCharArray(dstArray3, 2, items/2);
-    for (int i=2; i<items; i++) {
+    buf.getCharArray(dstArray3, 2, items / 2);
+    for (int i = 2; i < items; i++) {
       assertEquals(dstArray3[i], srcArray3[i]);
     }
 
     double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
     double[] dstArray4 = new double[items];
     buf.resetPosition();
-    buf.putDoubleArray(srcArray4, 2, items/2);
+    buf.putDoubleArray(srcArray4, 2, items / 2);
     buf.resetPosition();
-    buf.getDoubleArray(dstArray4, 2, items/2);
-    for (int i=2; i<items; i++) {
+    buf.getDoubleArray(dstArray4, 2, items / 2);
+    for (int i = 2; i < items; i++) {
       assertEquals(dstArray4[i], srcArray4[i], 0.0);
     }
 
     float[] srcArray5 = { (float)1.0, (float)-2.0, (float)3.0, (float)-4.0 };
     float[] dstArray5 = new float[items];
     buf.resetPosition();
-    buf.putFloatArray(srcArray5, 2, items/2);
+    buf.putFloatArray(srcArray5, 2, items / 2);
     buf.resetPosition();
-    buf.getFloatArray(dstArray5, 2, items/2);
-    for (int i=2; i<items; i++) {
+    buf.getFloatArray(dstArray5, 2, items / 2);
+    for (int i = 2; i < items; i++) {
       assertEquals(dstArray5[i], srcArray5[i], 0.0);
     }
 
     int[] srcArray6 = { 1, -2, 3, -4 };
     int[] dstArray6 = new int[items];
     buf.resetPosition();
-    buf.putIntArray(srcArray6, 2, items/2);
+    buf.putIntArray(srcArray6, 2, items / 2);
     buf.resetPosition();
-    buf.getIntArray(dstArray6, 2, items/2);
-    for (int i=2; i<items; i++) {
+    buf.getIntArray(dstArray6, 2, items / 2);
+    for (int i = 2; i < items; i++) {
       assertEquals(dstArray6[i], srcArray6[i]);
     }
 
     long[] srcArray7 = { 1, -2, 3, -4 };
     long[] dstArray7 = new long[items];
     buf.resetPosition();
-    buf.putLongArray(srcArray7, 2, items/2);
+    buf.putLongArray(srcArray7, 2, items / 2);
     buf.resetPosition();
-    buf.getLongArray(dstArray7, 2, items/2);
-    for (int i=2; i<items; i++) {
+    buf.getLongArray(dstArray7, 2, items / 2);
+    for (int i = 2; i < items; i++) {
       assertEquals(dstArray7[i], srcArray7[i]);
     }
 
     short[] srcArray8 = { 1, -2, 3, -4 };
     short[] dstArray8 = new short[items];
     buf.resetPosition();
-    buf.putShortArray(srcArray8, 2, items/2);
+    buf.putShortArray(srcArray8, 2, items / 2);
     buf.resetPosition();
-    buf.getShortArray(dstArray8, 2, items/2);
-    for (int i=2; i<items; i++) {
+    buf.getShortArray(dstArray8, 2, items / 2);
+    for (int i = 2; i < items; i++) {
       assertEquals(dstArray8[i], srcArray8[i]);
     }
   }
@@ -324,11 +320,9 @@
   @Test
   public void checkSetClearMemoryRegions() throws Exception {
     int memCapacity = 64; //must be 64
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh1.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       WritableBuffer buf = mem.asWritableBuffer();
       assertEquals(buf.getCapacity(), memCapacity);
-
       setClearMemoryRegionsTests(buf); //requires println enabled to visually check
       buf.resetPosition();
       for (int i = 0; i < memCapacity; i++) {
@@ -352,7 +346,7 @@
     buf.setStartPositionEnd(reg1Start, reg1Start, reg1Len);
     buf.fill(b1);
     buf.resetPosition();
-    for (int i=reg1Start; i<(reg1Len+reg1Start); i++) {
+    for (int i = reg1Start; i < (reg1Len + reg1Start); i++) {
       assertEquals(buf.getByte(), b1);
     }
     //println(buf.toHexString("Region1 to 5", reg1Start, reg1Len));
@@ -363,7 +357,7 @@
     buf.fill(b2);
     //println(mem.toHexString("Fill", 0, (int)mem.getCapacity()));
     buf.resetPosition();
-    for (int i=reg2Start; i<(reg2Start+reg2Len); i++) {
+    for (int i = reg2Start; i < (reg2Start + reg2Len); i++) {
       assertEquals(buf.getByte(), b2);
     }
     //println(buf.toHexString("Region2 to 7", reg2Start, reg2Len));
@@ -374,7 +368,7 @@
     buf.resetPosition();
     buf.clear();
     buf.resetPosition();
-    for (int i=reg1Start; i<(reg1Start+reg1Len); i++) {
+    for (int i = reg1Start; i < (reg1Start + reg1Len); i++) {
       assertEquals(buf.getByte(), zeroByte);
     }
     //println(buf.toHexString("Region1 cleared", reg1Start, reg1Len));
@@ -384,7 +378,7 @@
     buf.resetPosition();
     buf.clear();
     buf.resetPosition();
-    for (int i=reg2Start; i<(reg2Len+reg2Start); i++) {
+    for (int i = reg2Start; i < (reg2Len + reg2Start); i++) {
       assertEquals(buf.getByte(), zeroByte);
     }
     //println(buf.toHexString("Region2 cleared", reg2Start, reg2Len));
@@ -395,7 +389,7 @@
     buf.resetPosition();
     buf.fill(b4);
     buf.resetPosition();
-    for (int i=0; i<accessCapacity; i++) {
+    for (int i = 0; i < accessCapacity; i++) {
       assertEquals(buf.getByte(), b4);
     }
     //println(buf.toHexString("Region1 + Region2 all ones", 0, accessCapacity));
@@ -404,7 +398,7 @@
     buf.resetPosition();
     buf.clear();
     buf.resetPosition();
-    for (int i=0; i<accessCapacity; i++) {
+    for (int i = 0; i < accessCapacity; i++) {
       assertEquals(buf.getByte(), zeroByte);
     }
     //println(buf.toHexString("Region1 + Region2 cleared", 0, accessCapacity));
@@ -413,8 +407,7 @@
   @Test
   public void checkToHexStringAllMem() throws Exception {
     int memCapacity = 48; //must be 48
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh1.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       WritableBuffer buf = mem.asWritableBuffer();
       assertEquals(buf.getCapacity(), memCapacity);
       toHexStringAllMemTests(buf); //requires println enabled to visually check
@@ -425,7 +418,7 @@
   public static void toHexStringAllMemTests(WritableBuffer buf) {
     int memCapacity = (int)buf.getCapacity();
 
-    for (int i=0; i<memCapacity; i++) {
+    for (int i = 0; i < memCapacity; i++) {
       buf.putByte((byte)i);
     }
 
@@ -435,7 +428,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonMemoryTest.java
index 322352f..b617ccc 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonMemoryTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonMemoryTest.java
@@ -27,7 +27,6 @@
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
@@ -36,8 +35,7 @@
   @Test
   public void checkSetGet() throws Exception {
     int memCapacity = 16; //must be at least 8
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       assertEquals(mem.getCapacity(), memCapacity);
       setGetTests(mem);
     }
@@ -88,8 +86,7 @@
   @Test
   public void checkSetGetArrays() throws Exception {
     int memCapacity = 32;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       assertEquals(memCapacity, mem.getCapacity());
       setGetArraysTests(mem);
     }
@@ -168,75 +165,74 @@
   @Test
   public void checkSetGetPartialArraysWithOffset() throws Exception {
     int memCapacity = 32;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       assertEquals(memCapacity, mem.getCapacity());
       setGetPartialArraysWithOffsetTests(mem);
     }
   }
 
   public static void setGetPartialArraysWithOffsetTests(WritableMemory mem) {
-    int items= 4;
+    int items = 4;
     boolean[] srcArray1 = {true, false, true, false};
     boolean[] dstArray1 = new boolean[items];
-    mem.putBooleanArray(0, srcArray1, 2, items/2);
-    mem.getBooleanArray(0, dstArray1, 2, items/2);
+    mem.putBooleanArray(0, srcArray1, 2, items / 2);
+    mem.getBooleanArray(0, dstArray1, 2, items / 2);
     for (int i = 2; i < items; i++) {
       assertEquals(dstArray1[i], srcArray1[i]);
     }
 
     byte[] srcArray2 = { 1, -2, 3, -4 };
     byte[] dstArray2 = new byte[items];
-    mem.putByteArray(0, srcArray2, 2, items/2);
-    mem.getByteArray(0, dstArray2, 2, items/2);
+    mem.putByteArray(0, srcArray2, 2, items / 2);
+    mem.getByteArray(0, dstArray2, 2, items / 2);
     for (int i = 2; i < items; i++) {
       assertEquals(dstArray2[i], srcArray2[i]);
     }
 
     char[] srcArray3 = { 'A', 'B', 'C', 'D' };
     char[] dstArray3 = new char[items];
-    mem.putCharArray(0, srcArray3, 2, items/2);
-    mem.getCharArray(0, dstArray3, 2, items/2);
+    mem.putCharArray(0, srcArray3, 2, items / 2);
+    mem.getCharArray(0, dstArray3, 2, items / 2 );
     for (int i = 2; i < items; i++) {
       assertEquals(dstArray3[i], srcArray3[i]);
     }
 
     double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
     double[] dstArray4 = new double[items];
-    mem.putDoubleArray(0, srcArray4, 2, items/2);
-    mem.getDoubleArray(0, dstArray4, 2, items/2);
+    mem.putDoubleArray(0, srcArray4, 2, items / 2 );
+    mem.getDoubleArray(0, dstArray4, 2, items / 2 );
     for (int i = 2; i < items; i++) {
       assertEquals(dstArray4[i], srcArray4[i], 0.0);
     }
 
     float[] srcArray5 = { (float)1.0, (float)-2.0, (float)3.0, (float)-4.0 };
     float[] dstArray5 = new float[items];
-    mem.putFloatArray(0, srcArray5, 2, items/2);
-    mem.getFloatArray(0, dstArray5, 2, items/2);
+    mem.putFloatArray(0, srcArray5, 2, items / 2 );
+    mem.getFloatArray(0, dstArray5, 2, items / 2 );
     for (int i = 2; i < items; i++) {
       assertEquals(dstArray5[i], srcArray5[i], 0.0);
     }
 
     int[] srcArray6 = { 1, -2, 3, -4 };
     int[] dstArray6 = new int[items];
-    mem.putIntArray(0, srcArray6, 2, items/2);
-    mem.getIntArray(0, dstArray6, 2, items/2);
+    mem.putIntArray(0, srcArray6, 2, items / 2 );
+    mem.getIntArray(0, dstArray6, 2, items / 2 );
     for (int i = 2; i < items; i++) {
       assertEquals(dstArray6[i], srcArray6[i]);
     }
 
     long[] srcArray7 = { 1, -2, 3, -4 };
     long[] dstArray7 = new long[items];
-    mem.putLongArray(0, srcArray7, 2, items/2);
-    mem.getLongArray(0, dstArray7, 2, items/2);
+    mem.putLongArray(0, srcArray7, 2, items / 2 );
+    mem.getLongArray(0, dstArray7, 2, items / 2 );
     for (int i = 2; i < items; i++) {
       assertEquals(dstArray7[i], srcArray7[i]);
     }
 
     short[] srcArray8 = { 1, -2, 3, -4 };
     short[] dstArray8 = new short[items];
-    mem.putShortArray(0, srcArray8, 2, items/2);
-    mem.getShortArray(0, dstArray8, 2, items/2);
+    mem.putShortArray(0, srcArray8, 2, items / 2 );
+    mem.getShortArray(0, dstArray8, 2, items / 2 );
     for (int i = 2; i < items; i++) {
       assertEquals(dstArray8[i], srcArray8[i]);
     }
@@ -245,8 +241,7 @@
   @Test
   public void checkSetClearIsBits() throws Exception {
     int memCapacity = 8;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       assertEquals(memCapacity, mem.getCapacity());
       mem.clear();
       setClearIsBitsTests(mem);
@@ -284,38 +279,9 @@
   }
 
   @Test
-  public void checkAtomicMethods() throws Exception {
-    int memCapacity = 8;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
-      assertEquals(mem.getCapacity(), memCapacity);
-      atomicMethodTests(mem);
-    }
-  }
-
-  public static void atomicMethodTests(WritableMemory mem) {
-    mem.putLong(0, 500);
-    mem.getAndAddLong(0, 1);
-    assertEquals(mem.getLong(0), 501);
-
-    mem.putInt(0, 500);
-    boolean b = mem.compareAndSwapLong(0, 500, 501);
-    assertTrue(b);
-    assertEquals(mem.getLong(0), 501);
-
-    mem.putLong(0, 500);
-    long oldLong = mem.getAndSetLong(0, 501);
-    long newLong = mem.getLong(0);
-    assertEquals(oldLong, 500);
-    assertEquals(newLong, 501);
-  }
-
-  @Test
   public void checkSetClearMemoryRegions() throws Exception {
     int memCapacity = 64; //must be 64
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh1.getWritable();
-
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       setClearMemoryRegionsTests(mem); //requires println enabled to visually check
       for (int i = 0; i < memCapacity; i++) {
         assertEquals(mem.getByte(i), 0);
@@ -323,7 +289,7 @@
     }
   }
 
-  //enable println stmts to visually check
+  //enable println statements to visually check
   public static void setClearMemoryRegionsTests(WritableMemory mem) {
     int accessCapacity = (int)mem.getCapacity();
 
@@ -336,7 +302,7 @@
     //set region 1
     byte b1 = 5;
     mem.fill(reg1Start, reg1Len, b1);
-    for (int i = reg1Start; i < (reg1Len+reg1Start); i++) {
+    for (int i = reg1Start; i < (reg1Len + reg1Start); i++) {
       assertEquals(mem.getByte(i), b1);
     }
     //println(mem.toHexString("Region1 to 5", reg1Start, reg1Len));
@@ -345,7 +311,7 @@
     byte b2 = 7;
     mem.fill(reg2Start, reg2Len, b2);
     //println(mem.toHexString("Fill", 0, (int)mem.getCapacity()));
-    for (int i = reg2Start; i < (reg2Len+reg2Start); i++) {
+    for (int i = reg2Start; i < (reg2Len + reg2Start); i++) {
       assertEquals(mem.getByte(i), b2);
     }
     //println(mem.toHexString("Region2 to 7", reg2Start, reg2Len));
@@ -353,14 +319,14 @@
     //clear region 1
     byte zeroByte = 0;
     mem.clear(reg1Start, reg1Len);
-    for (int i = reg1Start; i < (reg1Len+reg1Start); i++) {
+    for (int i = reg1Start; i < (reg1Len + reg1Start); i++) {
       assertEquals(mem.getByte(i), zeroByte);
     }
     //println(mem.toHexString("Region1 cleared", reg1Start, reg1Len));
 
     //clear region 2
     mem.clear(reg2Start, reg2Len);
-    for (int i = reg2Start; i < (reg2Len+reg2Start); i++) {
+    for (int i = reg2Start; i < (reg2Len + reg2Start); i++) {
       assertEquals(mem.getByte(i), zeroByte);
     }
     //println(mem.toHexString("Region2 cleared", reg2Start, reg2Len));
@@ -368,7 +334,7 @@
     //set all to ones
     byte b4 = 127;
     mem.fill(b4);
-    for (int i=0; i<accessCapacity; i++) {
+    for (int i = 0; i < accessCapacity; i++) {
       assertEquals(mem.getByte(i), b4);
     }
     //println(mem.toHexString("Region1 + Region2 all ones", 0, accessCapacity));
@@ -384,8 +350,7 @@
   @Test
   public void checkToHexStringAllMem() throws Exception {
     int memCapacity = 48; //must be 48
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh1.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       toHexStringAllMemTests(mem); //requires println enabled to visually check
     }
   }
@@ -404,7 +369,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java
index 962b12f..9529c1a 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java
@@ -21,7 +21,6 @@
 
 import static org.testng.Assert.assertEquals;
 
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
@@ -43,8 +42,8 @@
     copyUsingDirectMemory(copyLongs, overlap, false);
     long end2_mS = System.currentTimeMillis();
 
-    println("CopyUp Time Sec: " + ((end1_mS - start_mS)/1000.0));
-    println("CopyDn Time Sec: " + ((end2_mS - end1_mS)/1000.0));
+    println("CopyUp Time Sec: " + ((end1_mS - start_mS) / 1000.0));
+    println("CopyDn Time Sec: " + ((end2_mS - end1_mS) / 1000.0));
   }
 
   @Test
@@ -59,8 +58,8 @@
     copyUsingDirectRegions(copyLongs, overlap, false);
     long end2_mS = System.currentTimeMillis();
 
-    println("CopyUp Time Sec: " + ((end1_mS - start_mS)/1000.0));
-    println("CopyDn Time Sec: " + ((end2_mS - end1_mS)/1000.0));
+    println("CopyUp Time Sec: " + ((end1_mS - start_mS) / 1000.0));
+    println("CopyDn Time Sec: " + ((end2_mS - end1_mS) / 1000.0));
   }
 
   private static final void copyUsingDirectMemory(long copyLongs, double overlap, boolean copyUp) throws Exception {
@@ -92,8 +91,7 @@
     println("CopyUp       : " + copyUp);
     println("Backing longs: " + backingLongs + "\t bytes: " + backingBytes);
 
-    try (WritableHandle backHandle = WritableMemory.allocateDirect(backingBytes)) {
-      WritableMemory backingMem = backHandle.getWritable();
+    try (WritableMemory backingMem = WritableMemory.allocateDirect(backingBytes)) {
       fill(backingMem); //fill mem with 0 thru copyLongs -1
       //listMem(backingMem, "Original");
       backingMem.copyTo(fromOffsetBytes, backingMem, toOffsetBytes, copyBytes);
@@ -132,8 +130,7 @@
     println("CopyUp       : " + copyUp);
     println("Backing longs: " + backingLongs + "\t bytes: " + backingBytes);
 
-    try (WritableHandle backHandle = WritableMemory.allocateDirect(backingBytes)) {
-      WritableMemory backingMem = backHandle.getWritable();
+    try (WritableMemory backingMem = WritableMemory.allocateDirect(backingBytes)) {
       fill(backingMem); //fill mem with 0 thru copyLongs -1
       //listMem(backingMem, "Original");
       WritableMemory reg1 = backingMem.writableRegion(fromOffsetBytes, copyBytes);
@@ -171,7 +168,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java
index fe37aad..3de76d7 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java
@@ -24,7 +24,6 @@
 
 import java.util.concurrent.ThreadLocalRandom;
 
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.Assert;
@@ -58,8 +57,7 @@
   public void directWSource() throws Exception {
     int k1 = 1 << 20; //longs
     int k2 = 2 * k1;
-    try (WritableHandle wrh = genWRH(k1, false)) {
-      WritableMemory srcMem = wrh.getWritable();
+    try (WritableMemory srcMem = genWRH(k1, false)) {
       WritableMemory dstMem = genMem(k2, true);
       srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
       check(dstMem, k1, k1, 1);
@@ -70,8 +68,7 @@
   public void directROSource() throws Exception {
     int k1 = 1 << 20; //longs
     int k2 = 2 * k1;
-    try (WritableHandle wrh = genWRH(k1, false)) {
-      Memory srcMem = wrh.get();
+    try (Memory srcMem = genWRH(k1, false)) {
       WritableMemory dstMem = genMem(k2, true);
       srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
       check(dstMem, k1, k1, 1);
@@ -84,11 +81,11 @@
     //gen baseMem of k1 longs w data
     WritableMemory baseMem = genMem(k1, false); //!empty
     //gen src region of k1/2 longs, off= k1/2
-    WritableMemory srcReg = baseMem.writableRegion((k1/2) << 3, (k1/2) << 3);
+    WritableMemory srcReg = baseMem.writableRegion((k1 / 2) << 3, (k1 / 2) << 3);
     WritableMemory dstMem = genMem(2 * k1, true); //empty
-    srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3);
+    srcReg.copyTo(0, dstMem, k1 << 3, (k1 / 2) << 3);
     //println(dstMem.toHexString("dstMem: ", k1 << 3, (k1/2) << 3));
-    check(dstMem, k1, k1/2, (k1/2) + 1);
+    check(dstMem, k1, k1 / 2, (k1 / 2) + 1);
   }
 
   @Test
@@ -97,23 +94,22 @@
     //gen baseMem of k1 longs w data
     WritableMemory baseMem = genMem(k1, false); //!empty
     //gen src region of k1/2 longs, off= k1/2
-    Memory srcReg = baseMem.region((k1/2) << 3, (k1/2) << 3);
+    Memory srcReg = baseMem.region((k1 / 2) << 3, (k1 / 2) << 3);
     WritableMemory dstMem = genMem(2 * k1, true); //empty
-    srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3);
-    check(dstMem, k1, k1/2, (k1/2) + 1);
+    srcReg.copyTo(0, dstMem, k1 << 3, (k1 / 2) << 3);
+    check(dstMem, k1, k1 / 2, (k1 / 2) + 1);
   }
 
   @Test
   public void directROSrcRegion() throws Exception {
     int k1 = 1 << 20; //longs
     //gen baseMem of k1 longs w data, direct
-    try (WritableHandle wrh = genWRH(k1, false)) {
-      Memory baseMem = wrh.get();
+    try (Memory baseMem = genWRH(k1, false)) {
       //gen src region of k1/2 longs, off= k1/2
-      Memory srcReg = baseMem.region((k1/2) << 3, (k1/2) << 3);
+      Memory srcReg = baseMem.region((k1 / 2) << 3, (k1 / 2) << 3);
       WritableMemory dstMem = genMem(2 * k1, true); //empty
-      srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3);
-      check(dstMem, k1, k1/2, (k1/2) + 1);
+      srcReg.copyTo(0, dstMem, k1 << 3, (k1 / 2) << 3);
+      check(dstMem, k1, k1 / 2, (k1 / 2) + 1);
     }
   }
 
@@ -150,18 +146,16 @@
     }
   }
 
-  private static WritableHandle genWRH(int longs, boolean empty) {
-    WritableHandle wrh = WritableMemory.allocateDirect(longs << 3);
-    WritableMemory mem = wrh.getWritable();
+  private static WritableMemory genWRH(int longs, boolean empty) {
+    WritableMemory mem = WritableMemory.allocateDirect(longs << 3);
     if (empty) {
       mem.clear();
     } else {
       for (int i = 0; i < longs; i++) { mem.putLong(i << 3, i + 1); }
     }
-    return wrh;
+    return mem;
   }
 
-
   private static WritableMemory genMem(int longs, boolean empty) {
     WritableMemory mem = WritableMemory.allocate(longs << 3);
     if (!empty) {
@@ -172,7 +166,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java
index 581bdda..6862bec 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java
@@ -40,10 +40,10 @@
  * uncovered this until August 2021.  Nonetheless, the fix involves instrumenting all the paths involved
  * in providing this callback mechanism for wrapped ByteBuffers.
  *
- * This issues was first identified in Druid Issue #11544 and then posted as DataSketches-java Issue #358.
- * But the actual source of the problem was in Memory.
+ * <p>This issue was first identified in Druid Issue #11544 and then posted as DataSketches-java Issue #358.
+ * But the actual source of the problem was in Memory.</p>
  *
- * This test mimics the Druid issue but at a much smaller scale.
+ * <p>This test mimics the Druid issue but at a much smaller scale.</p>
  *
  * @author Lee Rhodes
  *
@@ -61,7 +61,7 @@
 
     //Wrap bb into WritableMemory
     WritableMemory mem1 = WritableMemory.writableWrap(bb);
-    assertTrue(mem1.isDirect()); //confirm mem1 is off-heap
+    assertTrue(mem1.isDirectResource()); //confirm mem1 is off-heap
 
     //Acquire the DefaultMemoryRequestServer
     //NOTE: it is a policy decision to allow the DefaultMemoryServer to be set as a default.
@@ -77,7 +77,7 @@
     WritableMemory mem2 = svr.request(mem1, size2);
 
     //Confirm that mem2 is on the heap (the default) and 2X size1
-    assertFalse(mem2.isDirect());
+    assertFalse(mem2.isDirectResource());
     assertEquals(mem2.getCapacity(), size2);
 
     //Move data to new memory
@@ -94,7 +94,7 @@
     WritableMemory mem3 = svr.request(mem2, size3);
 
     //Confirm that mem3 is still on the heap and 2X of size2
-    assertFalse(mem3.isDirect());
+    assertFalse(mem3.isDirectResource());
     assertEquals(mem3.getCapacity(), size3);
 
     //Move data to new memory
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java
deleted file mode 100644
index 0cf345c..0000000
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-import static org.testng.Assert.assertFalse;
-
-import java.nio.ByteOrder;
-import java.util.IdentityHashMap;
-
-import org.apache.datasketches.memory.MemoryRequestServer;
-import org.apache.datasketches.memory.WritableHandle;
-import org.apache.datasketches.memory.WritableMemory;
-import org.testng.annotations.Test;
-
-/**
- * Examples of how to use the MemoryRequestServer with a memory hungry client.
- * @author Lee Rhodes
- */
-public class ExampleMemoryRequestServerTest {
-
-  /**
-   * This version is without a TWR block.all of the memory allocations are done through the MemoryRequestServer
-   * and each is closed by the MemoryClient when it is done with each.
-   * @throws Exception  thrown by automatic close() invocation on WritableHandle.
-   */
-  @Test
-  public void checkExampleMemoryRequestServer1() throws Exception {
-    int bytes = 8;
-    ExampleMemoryRequestServer svr = new ExampleMemoryRequestServer();
-    try (WritableHandle wh = WritableMemory.allocateDirect(8)) {
-      WritableMemory memStart = wh.getWritable();
-      WritableMemory wMem = svr.request(memStart, bytes);
-      MemoryClient client = new MemoryClient(wMem);
-      client.process();
-      svr.cleanup();
-    }
-  }
-
-  /**
-   * In this version the first memory allocation is done up front in a TWR block.
-   * And then the MemoryClient allocates new memories as needed, which are then closed
-   * by the MemoryClient when it is done with the new memory allocations.
-   * The initial allocation stays open until the end where it is closed at the end of the
-   * TWR scope.
-   * @throws Exception thrown by automatic close() invocation on WritableHandle.
-   */
-  @Test
-  public void checkExampleMemoryRequestServer2() throws Exception {
-    int bytes = 8;
-    ExampleMemoryRequestServer svr = new ExampleMemoryRequestServer();
-    try (WritableHandle handle = WritableMemory.allocateDirect(bytes, ByteOrder.nativeOrder(), svr)) {
-      WritableMemory memStart = handle.getWritable();
-      MemoryClient client = new MemoryClient(memStart);
-      client.process();
-      svr.cleanup(); //just to be sure all are closed.
-    }
-  }
-
-  @Test(expectedExceptions = IllegalArgumentException.class)
-  public void checkZeroCapacity() throws Exception {
-    ExampleMemoryRequestServer svr = new ExampleMemoryRequestServer();
-    try (WritableHandle wh = WritableMemory.allocateDirect(0, ByteOrder.nativeOrder(), svr)) {
-
-    }
-  }
-
-  /**
-   * This little client is never happy with how much memory it has been allocated and keeps
-   * requesting for more. When it does ask for more, it must copy its old data into the new
-   * memory, release the prior memory, and then continue working from there.
-   *
-   * <p>In reality, these memory requests should be quite rare.</p>
-   */
-  static class MemoryClient {
-    WritableMemory smallMem;
-    MemoryRequestServer svr;
-
-    MemoryClient(WritableMemory memStart) {
-      smallMem = memStart;
-      svr = memStart.getMemoryRequestServer();
-    }
-
-    void process() {
-      long cap1 = smallMem.getCapacity();
-      smallMem.fill((byte) 1);                //fill it, but not big enough
-      println(smallMem.toHexString("Small", 0, (int)cap1));
-
-      WritableMemory bigMem = svr.request(smallMem, 2 * cap1); //get bigger mem
-      long cap2 = bigMem.getCapacity();
-      smallMem.copyTo(0, bigMem, 0, cap1);    //copy data from small to big
-      svr.requestClose(smallMem, bigMem);     //done with smallMem, release it
-
-      bigMem.fill(cap1, cap1, (byte) 2);      //fill the rest of bigMem, still not big enough
-      println(bigMem.toHexString("Big", 0, (int)cap2));
-
-      WritableMemory giantMem = svr.request(bigMem, 2 * cap2); //get giant mem
-      long cap3 = giantMem.getCapacity();
-      bigMem.copyTo(0, giantMem, 0, cap2);    //copy data from small to big
-      svr.requestClose(bigMem, giantMem);     //done with bigMem, release it
-
-      giantMem.fill(cap2, cap2, (byte) 3);    //fill the rest of giantMem
-      println(giantMem.toHexString("Giant", 0, (int)cap3));
-      svr.requestClose(giantMem, null);                 //done with giantMem, release it
-    }
-  }
-
-  /**
-   * This example MemoryRequestServer is simplistic but demonstrates one of many ways to
-   * possibly manage the continuous requests for larger memory and to track the associations between
-   * handles and their associated memory.
-   */
-  public static class ExampleMemoryRequestServer implements MemoryRequestServer {
-    IdentityHashMap<WritableMemory, WritableHandle> map = new IdentityHashMap<>();
-
-    @Override
-    public WritableMemory request(WritableMemory currentWMem, long capacityBytes) {
-     ByteOrder order = currentWMem.getTypeByteOrder();
-     WritableHandle handle = WritableMemory.allocateDirect(capacityBytes, order, this);
-     WritableMemory wmem = handle.getWritable();
-     map.put(wmem, handle); //We track the newly allocated memory and its handle.
-     return wmem;
-    }
-
-    @Override
-    //here we actually release it, in reality it might be a lot more complex.
-    public void requestClose(WritableMemory memToRelease, WritableMemory newMemory) {
-      WritableHandle handle = map.get(memToRelease);
-      if (handle != null && handle.getWritable() == memToRelease) {
-        try {
-          handle.close();
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      }
-    }
-
-    public void cleanup() {
-      map.forEach((k,v) -> {
-        assertFalse(k.isValid()); //all entries in the map should be invalid
-        try {
-          v.close();
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      });
-    }
-  }
-
-  @Test
-  public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
-  }
-
-  /**
-   * @param s value to print
-   */
-  static void println(String s) {
-    //System.out.println(s); //disable here
-  }
-}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java
index d9e0773..842cab2 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java
@@ -19,7 +19,6 @@
 
 package org.apache.datasketches.memory.internal;
 
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -27,19 +26,17 @@
 
 public class IgnoredArrayOverflowTest {
 
-  private WritableHandle h;
   private WritableMemory memory;
-  private static final long MAX_SIZE = (1L << 10); // use 1L << 31 to test int overrange
+  private static final long MAX_SIZE = (1L << 10); // use 1L << 31 to test int over range
 
   @BeforeClass
   public void allocate() {
-    h = WritableMemory.allocateDirect(MAX_SIZE);
-    memory = h.getWritable();
+    memory = WritableMemory.allocateDirect(MAX_SIZE);
   }
 
   @AfterClass
-  public void close() throws Exception {
-    h.close();
+  public void close() {
+    memory.close();
   }
 
   @Test
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java
index f1ef17e..7951492 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java
@@ -34,8 +34,6 @@
 
 import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableBuffer;
-import org.apache.datasketches.memory.WritableHandle;
-import org.apache.datasketches.memory.WritableMapHandle;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
@@ -48,36 +46,36 @@
   private static final MemoryRequestServer dummyMemReqSvr = new DummyMemoryRequestServer();
 
   static class DummyMemoryRequestServer implements MemoryRequestServer {
+
     @Override
     public WritableMemory request(WritableMemory currentWMem, long capacityBytes) { return null; }
+
     @Override
     public void requestClose(WritableMemory memToClose, WritableMemory newMemory) { }
   }
 
   @Test
-  public void checkDirectLeafs() throws Exception {
+  public void checkDirectLeaves() throws Exception {
     long off = 0;
     long cap = 128;
     // Off Heap, Native order, No ByteBuffer, has MemReqSvr
-    try (WritableHandle wdh = WritableMemory.allocateDirect(cap, NBO, dummyMemReqSvr)) {
-      WritableMemory memNO = wdh.getWritable();
+    try (WritableMemory memNO = WritableMemory.allocateDirect(cap, NBO, dummyMemReqSvr)) {
       memNO.putShort(0, (short) 1);
-      assertNull(((BaseStateImpl)memNO).getUnsafeObject());
-      assertTrue(memNO.isDirect());
-      checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, true);
+      assertNull(((ResourceImpl)memNO).getUnsafeObject());
+      assertTrue(memNO.isDirectResource());
+      checkCombinations(memNO, off, cap, memNO.isDirectResource(), NBO, false, true);
     }
     // Off Heap, Non Native order, No ByteBuffer, has MemReqSvr
-    try (WritableHandle wdh = WritableMemory.allocateDirect(cap, NNBO, dummyMemReqSvr)) {
-      WritableMemory memNNO = wdh.getWritable();
+    try (WritableMemory memNNO = WritableMemory.allocateDirect(cap, NNBO, dummyMemReqSvr)) {
       memNNO.putShort(0, (short) 1);
-      assertNull(((BaseStateImpl)memNNO).getUnsafeObject());
-      assertTrue(memNNO.isDirect());
-      checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, true);
+      assertNull(((ResourceImpl)memNNO).getUnsafeObject());
+      assertTrue(memNNO.isDirectResource());
+      checkCombinations(memNNO, off, cap, memNNO.isDirectResource(), NNBO, false, true);
     }
   }
 
   @Test
-  public void checkByteBufferLeafs() {
+  public void checkByteBufferLeaves() {
     long off = 0;
     long cap = 128;
     //BB on heap, native order, has ByteBuffer, has MemReqSvr
@@ -85,40 +83,40 @@
     bb.order(NBO);
     bb.putShort(0, (short) 1);
     WritableMemory mem = WritableMemory.writableWrap(bb, NBO, dummyMemReqSvr);
-    assertEquals(bb.isDirect(), mem.isDirect());
-    assertNotNull(((BaseStateImpl)mem).getUnsafeObject());
-    checkCombinations(mem, off, cap, mem.isDirect(), mem.getTypeByteOrder(), true, true);
+    assertEquals(bb.isDirect(), mem.isDirectResource());
+    assertNotNull(((ResourceImpl)mem).getUnsafeObject());
+    checkCombinations(mem, off, cap, mem.isDirectResource(), mem.getByteOrder(), true, true);
 
     //BB off heap, native order, has ByteBuffer, has MemReqSvr
     ByteBuffer dbb = ByteBuffer.allocateDirect((int)cap);
     dbb.order(NBO);
     dbb.putShort(0, (short) 1);
     mem = WritableMemory.writableWrap(dbb, NBO, dummyMemReqSvr);
-    assertEquals(dbb.isDirect(), mem.isDirect());
-    assertNull(((BaseStateImpl)mem).getUnsafeObject());
-    checkCombinations(mem, off, cap,  mem.isDirect(), mem.getTypeByteOrder(), true, true);
+    assertEquals(dbb.isDirect(), mem.isDirectResource());
+    assertNull(((ResourceImpl)mem).getUnsafeObject());
+    checkCombinations(mem, off, cap,  mem.isDirectResource(), mem.getByteOrder(), true, true);
 
     //BB on heap, non native order, has ByteBuffer, has MemReqSvr
     bb = ByteBuffer.allocate((int)cap);
     bb.order(NNBO);
     bb.putShort(0, (short) 1);
     mem = WritableMemory.writableWrap(bb, NNBO, dummyMemReqSvr);
-    assertEquals(bb.isDirect(), mem.isDirect());
-    assertNotNull(((BaseStateImpl)mem).getUnsafeObject());
-    checkCombinations(mem, off, cap, mem.isDirect(), mem.getTypeByteOrder(), true, true);
+    assertEquals(bb.isDirect(), mem.isDirectResource());
+    assertNotNull(((ResourceImpl)mem).getUnsafeObject());
+    checkCombinations(mem, off, cap, mem.isDirectResource(), mem.getByteOrder(), true, true);
 
     //BB off heap, non native order, has ByteBuffer, has MemReqSvr
     dbb = ByteBuffer.allocateDirect((int)cap);
     dbb.order(NNBO);
     dbb.putShort(0, (short) 1);
     mem = WritableMemory.writableWrap(dbb, NNBO, dummyMemReqSvr);
-    assertEquals(dbb.isDirect(), mem.isDirect());
-    assertNull(((BaseStateImpl)mem).getUnsafeObject());
-    checkCombinations(mem, off, cap,  mem.isDirect(), mem.getTypeByteOrder(), true, true);
+    assertEquals(dbb.isDirect(), mem.isDirectResource());
+    assertNull(((ResourceImpl)mem).getUnsafeObject());
+    checkCombinations(mem, off, cap,  mem.isDirectResource(), mem.getByteOrder(), true, true);
   }
 
   @Test
-  public void checkMapLeafs() throws Exception {
+  public void checkMapLeaves() throws Exception {
     long off = 0;
     long cap = 128;
     File file = new File("TestFile2.bin");
@@ -134,39 +132,37 @@
     assertTrue(file.isFile());
     file.deleteOnExit();  //comment out if you want to examine the file.
     // Off Heap, Native order, No ByteBuffer, No MemReqSvr
-    try (WritableMapHandle wmh = WritableMemory.writableMap(file, off, cap, NBO)) {
-      WritableMemory memNO = wmh.getWritable();
+    try (WritableMemory memNO = WritableMemory.writableMap(file, off, cap, NBO)) {
       memNO.putShort(0, (short) 1);
-      assertNull(((BaseStateImpl)memNO).getUnsafeObject());
-      assertTrue(memNO.isDirect());
-      checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, false);
+      assertNull(((ResourceImpl)memNO).getUnsafeObject());
+      assertTrue(memNO.isDirectResource());
+      checkCombinations(memNO, off, cap, memNO.isDirectResource(), NBO, false, false);
     }
     // Off heap, Non Native order, No ByteBuffer, no MemReqSvr
-    try (WritableMapHandle wmh = WritableMemory.writableMap(file, off, cap, NNBO)) {
-      WritableMemory memNNO = wmh.getWritable();
+    try (WritableMemory memNNO = WritableMemory.writableMap(file, off, cap, NNBO)) {
       memNNO.putShort(0, (short) 1);
-      assertNull(((BaseStateImpl)memNNO).getUnsafeObject());
-      assertTrue(memNNO.isDirect());
-      checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, false);
+      assertNull(((ResourceImpl)memNNO).getUnsafeObject());
+      assertTrue(memNNO.isDirectResource());
+      checkCombinations(memNNO, off, cap, memNNO.isDirectResource(), NNBO, false, false);
     }
   }
 
   @Test
-  public void checkHeapLeafs() {
+  public void checkHeapLeaves() {
     long off = 0;
     long cap = 128;
     // On Heap, Native order, No ByteBuffer, No MemReqSvr
     WritableMemory memNO = WritableMemory.allocate((int)cap); //assumes NBO
     memNO.putShort(0, (short) 1);
-    assertNotNull(((BaseStateImpl)memNO).getUnsafeObject());
-    assertFalse(memNO.isDirect());
-    checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, false);
+    assertNotNull(((ResourceImpl)memNO).getUnsafeObject());
+    assertFalse(memNO.isDirectResource());
+    checkCombinations(memNO, off, cap, memNO.isDirectResource(), NBO, false, false);
     // On Heap, Non-native order, No ByteBuffer, No MemReqSvr
     WritableMemory memNNO = WritableMemory.allocate((int)cap, NNBO);
     memNNO.putShort(0, (short) 1);
-    assertNotNull(((BaseStateImpl)memNNO).getUnsafeObject());
-    assertFalse(memNNO.isDirect());
-    checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, false);
+    assertNotNull(((ResourceImpl)memNNO).getUnsafeObject());
+    assertFalse(memNNO.isDirectResource());
+    checkCombinations(memNNO, off, cap, memNNO.isDirectResource(), NNBO, false, false);
   }
 
   private static void checkCombinations(WritableMemory mem, long off, long cap,
@@ -175,24 +171,27 @@
 
     assertEquals(mem.writableRegion(off, cap, bo).getShort(0), 1);
     assertEquals(mem.writableRegion(off, cap, oo).getShort(0), 256);
-
     assertEquals(mem.asWritableBuffer(bo).getShort(0), 1);
     assertEquals(mem.asWritableBuffer(oo).getShort(0), 256);
+    assertEquals(mem.getTotalOffset(), 0);
 
-    ByteBuffer bb = mem.getByteBuffer();
+    ByteBuffer bb = ((ResourceImpl)mem).getByteBuffer();
     assertTrue( hasByteBuffer ? bb != null : bb == null);
 
-    assertTrue(mem.getTypeByteOrder() == bo);
+    assertTrue(mem.getByteOrder() == bo);
 
     if (hasMemReqSvr) { assertTrue(mem.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
+    else { assertNull(mem.getMemoryRequestServer()); }
 
-    Object obj = ((BaseStateImpl)mem).getUnsafeObject();
+    Object obj = ((ResourceImpl)mem).getUnsafeObject();
     if (direct) {
-      assertTrue(mem.isDirect());
+      assertTrue(mem.isDirectResource());
       assertNull(obj);
+      assertTrue(((ResourceImpl)mem).getCumulativeOffset(0) != 0);
     } else {
-      assertFalse(mem.isDirect());
+      assertFalse(mem.isDirectResource());
       assertNotNull(obj);
+      assertTrue(((ResourceImpl)mem).getCumulativeOffset(0) != 0);
     }
 
     assertTrue(mem.isValid() == true);
@@ -203,21 +202,25 @@
     assertEquals(buf.writableRegion(off, cap, oo).getShort(0), 256);
     assertEquals(buf.writableDuplicate(bo).getShort(0), 1);
     assertEquals(buf.writableDuplicate(oo).getShort(0), 256);
+    assertEquals(buf.getTotalOffset(), 0);
 
-    bb = buf.getByteBuffer();
+    bb = ((ResourceImpl)buf).getByteBuffer();
     assertTrue(hasByteBuffer ? bb != null : bb == null);
 
-    assertTrue(buf.getTypeByteOrder() == bo);
+    assertTrue(buf.getByteOrder() == bo);
 
     if (hasMemReqSvr) { assertTrue(buf.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
+    else { assertNull(buf.getMemoryRequestServer()); }
 
-    obj = ((BaseStateImpl)buf).getUnsafeObject();
+    obj = ((ResourceImpl)buf).getUnsafeObject();
     if (direct) {
-      assertTrue(buf.isDirect());
+      assertTrue(buf.isDirectResource());
       assertNull(obj);
+      assertTrue(((ResourceImpl)buf).getCumulativeOffset(0) != 0);
     } else {
-      assertFalse(buf.isDirect());
+      assertFalse(buf.isDirectResource());
       assertNotNull(obj);
+      assertTrue(((ResourceImpl)buf).getCumulativeOffset(0) != 0);
     }
 
     assertTrue(buf.isValid() == true);
@@ -229,20 +232,22 @@
     assertEquals(nnMem.asWritableBuffer(bo).getShort(0), 1);
     assertEquals(nnMem.asWritableBuffer(oo).getShort(0), 256);
 
-    bb = nnMem.getByteBuffer();
+    bb = ((ResourceImpl)nnMem).getByteBuffer();
     assertTrue( hasByteBuffer ? bb != null : bb == null);
 
-    assertTrue(nnMem.getTypeByteOrder() == oo);
+    assertTrue(nnMem.getByteOrder() == oo);
 
     if (hasMemReqSvr) { assertTrue(nnMem.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
 
-    obj = ((BaseStateImpl)nnMem).getUnsafeObject();
+    obj = ((ResourceImpl)nnMem).getUnsafeObject();
     if (direct) {
-      assertTrue(nnMem.isDirect());
+      assertTrue(nnMem.isDirectResource());
       assertNull(obj);
+      assertTrue(((ResourceImpl)nnMem).getCumulativeOffset(0) != 0);
     } else {
-      assertFalse(nnMem.isDirect());
+      assertFalse(nnMem.isDirectResource());
       assertNotNull(obj);
+      assertTrue(((ResourceImpl)nnMem).getCumulativeOffset(0) != 0);
     }
 
     assertTrue(nnMem.isValid() == true);
@@ -254,20 +259,22 @@
     assertEquals(nnBuf.writableDuplicate(bo).getShort(0), 1);
     assertEquals(nnBuf.writableDuplicate(oo).getShort(0), 256);
 
-    bb = nnBuf.getByteBuffer();
+    bb = ((ResourceImpl)nnBuf).getByteBuffer();
     assertTrue( hasByteBuffer ? bb != null : bb == null);
 
-    assertTrue(nnBuf.getTypeByteOrder() == oo);
+    assertTrue(nnBuf.getByteOrder() == oo);
 
     if (hasMemReqSvr) { assertTrue(nnBuf.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
 
-    obj = ((BaseStateImpl)nnBuf).getUnsafeObject();
+    obj = ((ResourceImpl)nnBuf).getUnsafeObject();
     if (direct) {
-      assertTrue(nnBuf.isDirect());
+      assertTrue(nnBuf.isDirectResource());
       assertNull(obj);
+      assertTrue(((ResourceImpl)nnBuf).getCumulativeOffset(0) != 0);
     } else {
-      assertFalse(nnBuf.isDirect());
+      assertFalse(nnBuf.isDirectResource());
       assertNotNull(obj);
+      assertTrue(((ResourceImpl)nnBuf).getCumulativeOffset(0) != 0);
     }
 
     assertTrue(nnBuf.isValid() == true);
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java
index 1362f44..7ddf404 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java
@@ -19,6 +19,7 @@
 
 package org.apache.datasketches.memory.internal;
 
+import org.apache.datasketches.memory.MemoryBoundsException;
 import org.apache.datasketches.memory.WritableBuffer;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
@@ -27,179 +28,83 @@
 
   private final WritableBuffer writableBuffer = WritableMemory.allocate(8).asWritableBuffer();
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetBoolean() {
-    writableBuffer.getBoolean(7);
-    try {
-      writableBuffer.getBoolean(8);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.getBoolean(8);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutBoolean() {
-    writableBuffer.putBoolean(7, true);
-    try {
-      writableBuffer.putBoolean(8, true);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.putBoolean(8, true);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetByte() {
-    writableBuffer.getByte(7);
-    try {
-      writableBuffer.getByte(8);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.getByte(8);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutByte() {
-    writableBuffer.putByte(7, (byte) 1);
-    try {
-      writableBuffer.putByte(8, (byte) 1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.putByte(8, (byte) 1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetChar() {
-    writableBuffer.getChar(6);
-    try {
-      writableBuffer.getChar(7);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.getChar(7);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutChar() {
-    writableBuffer.putChar(6, 'a');
-    try {
-      writableBuffer.putChar(7, 'a');
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.putChar(7, 'a');
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetShort() {
-    writableBuffer.getShort(6);
-    try {
-      writableBuffer.getShort(7);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.getShort(7);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutShort() {
-    writableBuffer.putShort(6, (short) 1);
-    try {
-      writableBuffer.putShort(7, (short) 1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.putShort(7, (short) 1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetInt() {
-    writableBuffer.getInt(4);
-    try {
-      writableBuffer.getInt(5);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.getInt(5);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutInt() {
-    writableBuffer.putInt(4, 1);
-    try {
-      writableBuffer.putInt(5, 1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.putInt(5, 1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetFloat() {
-    writableBuffer.getFloat(4);
-    try {
-      writableBuffer.getFloat(5);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.getFloat(5);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutFloat() {
-    writableBuffer.putFloat(4, 1f);
-    try {
-      writableBuffer.putFloat(5, 1f);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.putFloat(5, 1f);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetLong() {
-    writableBuffer.getLong(0);
-    try {
-      writableBuffer.getLong(1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.getLong(1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutLong() {
-    writableBuffer.putLong(0, 1L);
-    try {
-      writableBuffer.putLong(1, 1L);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.putLong(1, 1L);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testGetDouble() {
-    writableBuffer.getDouble(0);
-    try {
-      writableBuffer.getDouble(1);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.getDouble(1);
   }
 
-  @Test
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void testPutDouble() {
-    writableBuffer.putDouble(0, 1d);
-    try {
-      writableBuffer.putDouble(1, 1d);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
+    writableBuffer.putDouble(1, 1d);
   }
 }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCloseExceptionTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCloseExceptionTest.java
index 249d432..b4d5980 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCloseExceptionTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCloseExceptionTest.java
@@ -19,21 +19,7 @@
 
 package org.apache.datasketches.memory.internal;
 
-import org.apache.datasketches.memory.MemoryCloseException;
-import org.testng.annotations.Test;
-
 public class MemoryCloseExceptionTest {
 
-  @Test
-  public void checkNoArgs() {
-    try {
-      throw new MemoryCloseException();
-    } catch (final MemoryCloseException e) {}
-
-    try {
-      throw new MemoryCloseException("Test Exception");
-    } catch (final MemoryCloseException e) {}
-  }
 }
 
-
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java
index 553c432..1a2ae5d 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java
@@ -20,11 +20,12 @@
 package org.apache.datasketches.memory.internal;
 
 import java.io.File;
-import java.io.RandomAccessFile;
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.nio.file.StandardOpenOption;
 
-import org.apache.datasketches.memory.MapHandle;
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.ReadOnlyException;
 import org.apache.datasketches.memory.WritableMemory;
@@ -36,42 +37,42 @@
 
   final WritableMemory mem = (WritableMemory) Memory.wrap(new byte[8]);
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutByte() {
     mem.putByte(0, (byte) 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutBoolean() {
     mem.putBoolean(0, true);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutShort() {
     mem.putShort(0, (short) 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutChar() {
     mem.putChar(0, (char) 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutInt() {
     mem.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutLong() {
     mem.putLong(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutFloat() {
     mem.putFloat(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testPutDouble() {
     mem.putDouble(0, 1);
   }
@@ -118,110 +119,132 @@
 
   // Now, test that various ways to obtain a read-only memory produce a read-only memory indeed
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testWritableMemoryRegion() {
     WritableMemory mem1 = (WritableMemory) WritableMemory.allocate(8).region(0, 8);
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testByteArrayWrap() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new byte[8]);
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testByteArrayWrapWithBO() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new byte[8], ByteOrder.nativeOrder());
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testByteArrayWrapWithOffsetsAndBO() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new byte[8], 0, 4, ByteOrder.nativeOrder());
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testBooleanArrayWrap() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new boolean[8]);
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testShortArrayWrap() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new short[8]);
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testCharArrayWrap() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new char[8]);
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testIntArrayWrap() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new int[8]);
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testLongArrayWrap() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new long[8]);
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testFloatArrayWrap() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new float[8]);
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testDoubleArrayWrap() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(new double[8]);
     mem1.putInt(0, 1);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testByteBufferWrap() {
     WritableMemory mem1 = (WritableMemory) Memory.wrap(ByteBuffer.allocate(8));
     mem1.putInt(0, 1);
   }
 
-  //@SuppressWarnings("resource")
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = ReadOnlyException.class)
   public void testMapFile() throws Exception {
-    File tempFile = File.createTempFile("test", null);
-    tempFile.deleteOnExit();
-    try (RandomAccessFile raf = new RandomAccessFile(tempFile, "rw")) {
-      raf.setLength(8);
-      //System.out.println(UtilTest.getFileAttributes(tempFile));
-      try (MapHandle h = Memory.map(tempFile)) {
-        ((WritableMemory) h.get()).putInt(0, 1);
-      }
+    File tempFile;
+    try {
+      tempFile = File.createTempFile("test", ".tmp", null);
+      Files.write(tempFile.toPath(), "ipsum".getBytes(), StandardOpenOption.APPEND);
+      //tempFile.setReadOnly();
+    } catch (IllegalArgumentException | IOException | SecurityException e) { throw new RuntimeException(e); }
+    try (Memory mem = Memory.map(tempFile)) { //Memory is RO
+      ((WritableMemory) mem).putInt(0, 1);
     }
+    tempFile.delete();
   }
 
-  @SuppressWarnings("resource")
-  @Test(expectedExceptions = AssertionError.class)
-  public void testMapFileWithOffsetsAndBO() throws Exception {
-    File tempFile = File.createTempFile("test", "test");
-    tempFile.deleteOnExit();
-    new RandomAccessFile(tempFile, "rw").setLength(8);
-    try (MapHandle h = Memory.map(tempFile, 0, 4, ByteOrder.nativeOrder())) {
-      ((WritableMemory) h.get()).putInt(0, 1);
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testWritableMapWithROFile() {
+    File tempFile;
+    try {
+      tempFile = File.createTempFile("test", ".tmp", null);
+      Files.write(tempFile.toPath(), "ipsum".getBytes(), StandardOpenOption.APPEND);
+      tempFile.setReadOnly();
+    } catch (IllegalArgumentException | IOException | SecurityException e) { throw new RuntimeException(e); }
+    try (WritableMemory mem = WritableMemory.writableMap(tempFile)) { //File is RO
+      mem.putInt(0, 1);
     }
+    tempFile.delete();
   }
 
-  @SuppressWarnings("resource")
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testMapFileWithOffsetsAndBO() {
+    File tempFile;
+    try {
+      tempFile = File.createTempFile("test", ".tmp", null);
+      Files.write(tempFile.toPath(), "ipsum".getBytes(), StandardOpenOption.APPEND);
+      //tempFile.setReadOnly();
+    } catch (IllegalArgumentException | IOException | SecurityException e) { throw new RuntimeException(e); }
+    try (Memory mem = Memory.map(tempFile, 0, 4, ByteOrder.nativeOrder())) { //Memory is RO
+      ((WritableMemory) mem).putInt(0, 1);
+    }
+    tempFile.delete();
+  }
+
   @Test(expectedExceptions = IllegalArgumentException.class)
-  public void testMapFileBeyondTheFileSize() throws Exception {
-    File tempFile = File.createTempFile("test", "test");
-    tempFile.deleteOnExit();
-    new RandomAccessFile(tempFile, "rw").setLength(8);
-    try (MapHandle unused = Memory.map(tempFile, 0, 16, ByteOrder.nativeOrder())) {
+  public void testMapFileBeyondTheFileSize() {
+    File tempFile;
+    try {
+      tempFile = File.createTempFile("test", ".tmp", null);
+      Files.write(tempFile.toPath(), "ipsum".getBytes(), StandardOpenOption.APPEND);
+      //tempFile.setReadOnly();
+    } catch (IllegalArgumentException | IOException | SecurityException e) { throw new RuntimeException(e); }
+    try (Memory mem = Memory.map(tempFile, 0, 16, ByteOrder.nativeOrder())) {
+      //Read-only mode and requested map length is greater than current file length:
+      //  Requested Length = 16, Current File Length = 5
     }
+    tempFile.delete();
   }
 }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java
index 8a3d472..a211db6 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java
@@ -23,30 +23,28 @@
 
 package org.apache.datasketches.memory.internal;
 
-import static org.apache.datasketches.memory.internal.Util.getResourceFile;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
-import java.io.File;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.List;
 
-import org.apache.datasketches.memory.BaseState;
-import org.apache.datasketches.memory.MapHandle;
+import org.apache.datasketches.memory.DefaultMemoryRequestServer;
 import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.Resource;
 import org.apache.datasketches.memory.WritableBuffer;
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 import org.testng.collections.Lists;
 
 public class MemoryTest {
-  private static final String LS = System.getProperty("line.separator");
+  private static final String LS = Util.LS;
 
   @BeforeClass
   public void setReadOnly() {
@@ -56,8 +54,7 @@
   @Test
   public void checkDirectRoundTrip() throws Exception {
     int n = 1024; //longs
-    try (WritableHandle wh = WritableMemory.allocateDirect(n * 8)) {
-      WritableMemory mem = wh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(n * 8)) {
       for (int i = 0; i < n; i++) {
         mem.putLong(i * 8, i);
       }
@@ -210,8 +207,8 @@
     ByteBuffer bb = ByteBuffer.allocate(n * 8);
     bb.order(ByteOrder.BIG_ENDIAN);
     Memory mem = Memory.wrap(bb);
-    assertFalse(mem.getTypeByteOrder() == ByteOrder.nativeOrder());
-    assertEquals(mem.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertFalse(mem.getByteOrder() == ByteOrder.nativeOrder());
+    assertEquals(mem.getByteOrder(), ByteOrder.BIG_ENDIAN);
   }
 
   @Test
@@ -319,88 +316,37 @@
     }
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = IllegalStateException.class)
   public void checkParentUseAfterFree() throws Exception {
     int bytes = 64 * 8;
-    WritableHandle wh = WritableMemory.allocateDirect(bytes);
-    WritableMemory wmem = wh.getWritable();
-    wh.close();
-    //with -ea assert: Memory not valid.
-    //with -da sometimes segfaults, sometimes passes!
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes);
+    wmem.close();
     wmem.getLong(0);
   }
 
-  @Test(expectedExceptions = AssertionError.class)
+  @Test(expectedExceptions = IllegalStateException.class)
   public void checkRegionUseAfterFree() throws Exception {
     int bytes = 64;
-    WritableHandle wh = WritableMemory.allocateDirect(bytes);
-    Memory wmem = wh.get();
-    Memory region = wmem.region(0L, bytes);
-    wh.close();
-    //with -ea assert: Memory not valid.
-    //with -da sometimes segfaults, sometimes passes!
+    Memory mem = WritableMemory.allocateDirect(bytes);
+    Memory region = mem.region(0L, bytes);
+    mem.close();
     region.getByte(0);
   }
 
   @Test
-  public void checkMonitorDirectStats() throws Exception {
-    int bytes = 1024;
-    long curAllocations = BaseState.getCurrentDirectMemoryAllocations();
-    long curAllocated   = BaseState.getCurrentDirectMemoryAllocated();
-    if (curAllocations != 0) { System.err.println(curAllocations + " should be zero!"); }
-    WritableHandle wh1 = WritableMemory.allocateDirect(bytes);
-    WritableHandle wh2 = WritableMemory.allocateDirect(bytes);
-    assertEquals(BaseState.getCurrentDirectMemoryAllocations(), 2L + curAllocations);
-    assertEquals(BaseState.getCurrentDirectMemoryAllocated(), 2 * bytes + curAllocated);
-
-    wh1.close();
-    assertEquals(BaseState.getCurrentDirectMemoryAllocations(), 1L + curAllocations);
-    assertEquals(BaseState.getCurrentDirectMemoryAllocated(), bytes + curAllocated);
-
-    wh2.close();
-    wh2.close(); //check that it doesn't go negative.
-    //even though the handles are closed, these methods are static access
-    assertEquals(BaseState.getCurrentDirectMemoryAllocations(), 0L + curAllocations);
-    assertEquals(BaseState.getCurrentDirectMemoryAllocated(), 0L + curAllocated);
-  }
-
-  @Test
-  public void checkMonitorDirectMapStats() throws Exception {
-    File file = getResourceFile("GettysburgAddress.txt");
-    long bytes = file.length();
-
-    MapHandle mmh1 = Memory.map(file);
-    MapHandle mmh2 = Memory.map(file);
-
-    assertEquals(BaseState.getCurrentDirectMemoryMapAllocations(), 2L);
-    assertEquals(BaseState.getCurrentDirectMemoryMapAllocated(), 2 * bytes);
-
-    mmh1.close();
-    assertEquals(BaseState.getCurrentDirectMemoryMapAllocations(), 1L);
-    assertEquals(BaseState.getCurrentDirectMemoryMapAllocated(), bytes);
-
-    mmh2.close();
-    mmh2.close(); //check that it doesn't go negative.
-    //even though the handles are closed, these methods are static access
-    assertEquals(BaseState.getCurrentDirectMemoryMapAllocations(), 0L);
-    assertEquals(BaseState.getCurrentDirectMemoryMapAllocated(), 0L);
-  }
-
-  @Test
   public void checkMemReqSvr() throws Exception {
     WritableMemory wmem;
     WritableBuffer wbuf;
-    if (BaseState.defaultMemReqSvr == null) { //This is a policy choice
+    if (Resource.defaultMemReqSvr == null) { //This is a policy choice
       //ON HEAP
       wmem = WritableMemory.writableWrap(new byte[16]);
       assertNull(wmem.getMemoryRequestServer());
       wbuf = wmem.asWritableBuffer();
       assertNull(wbuf.getMemoryRequestServer());
       //OFF HEAP
-      try (WritableHandle wdh = WritableMemory.allocateDirect(16)) { //OFF HEAP
-        wmem = wdh.getWritable();
-        assertNull(wmem.getMemoryRequestServer());
-        wbuf = wmem.asWritableBuffer();
+      try (WritableMemory wmem2 = WritableMemory.allocateDirect(16)) { //OFF HEAP
+        assertNull(wmem2.getMemoryRequestServer());
+        wbuf = wmem2.asWritableBuffer();
         assertNull(wbuf.getMemoryRequestServer());
       }
       //ByteBuffer
@@ -409,33 +355,28 @@
       assertNull(wmem.getMemoryRequestServer());
       wbuf = wmem.asWritableBuffer();
       assertNull(wbuf.getMemoryRequestServer());
-    } else {
-      //ON HEAP
-      wmem = WritableMemory.writableWrap(new byte[16]);
-      assertNotNull(wmem.getMemoryRequestServer());
-      wbuf = wmem.asWritableBuffer();
-      assertNotNull(wbuf.getMemoryRequestServer());
-      //OFF HEAP
-      try (WritableHandle wdh = WritableMemory.allocateDirect(16)) {
-        WritableMemory wmem2 = wdh.getWritable();
-        assertNotNull(wmem2.getMemoryRequestServer());
-        wbuf = wmem.asWritableBuffer();
-        assertNotNull(wbuf.getMemoryRequestServer());
-      }
-      //ByteBuffer
-      ByteBuffer bb = ByteBuffer.allocate(16);
-      wmem = WritableMemory.writableWrap(bb);
-      assertNotNull(wmem.getMemoryRequestServer());
+    }
+
+    MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+
+    //ON HEAP
+    wmem = WritableMemory.writableWrap(new byte[16], 0, 16, Util.NATIVE_BYTE_ORDER, memReqSvr);
+    assertNotNull(wmem.getMemoryRequestServer());
+    wbuf = wmem.asWritableBuffer();
+    assertNotNull(wbuf.getMemoryRequestServer());
+    //OFF HEAP
+    try (WritableMemory wmem3 = WritableMemory.allocateDirect(16, Util.NATIVE_BYTE_ORDER, memReqSvr)) {
+      assertNotNull(wmem3.getMemoryRequestServer());
       wbuf = wmem.asWritableBuffer();
       assertNotNull(wbuf.getMemoryRequestServer());
     }
-  }
+    //ByteBuffer
+    ByteBuffer bb = ByteBuffer.allocate(16);
+    wmem = WritableMemory.writableWrap(bb, Util.NATIVE_BYTE_ORDER, memReqSvr);
+    assertNotNull(wmem.getMemoryRequestServer());
+    wbuf = wmem.asWritableBuffer();
+    assertNotNull(wbuf.getMemoryRequestServer());
 
-  @Test
-  public void checkHashCode() {
-    WritableMemory wmem = WritableMemory.allocate(32 + 7);
-    int hc = wmem.hashCode();
-    assertEquals(hc, -1895166923);
   }
 
   @Test
@@ -444,9 +385,9 @@
     WritableMemory wmem = WritableMemory.allocate(len);
     for (int i = 0; i < len; i++) { wmem.putByte(i, (byte) i); }
     assertTrue(wmem.equalTo(0, wmem, 0, len));
-    assertFalse(wmem.equalTo(0, wmem, len/2, len/2));
+    assertFalse(wmem.equalTo(0, wmem, len / 2, len / 2));
     assertEquals(wmem.compareTo(0, len, wmem, 0, len), 0);
-    assertTrue(wmem.compareTo(0, 0, wmem, len/2, len/2) < 0);
+    assertTrue(wmem.compareTo(0, 0, wmem, len / 2, len / 2) < 0);
   }
 
   @Test
@@ -471,7 +412,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   static void println(final Object o) {
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryWriteToTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryWriteToTest.java
index 78e51ab..5483036 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryWriteToTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryWriteToTest.java
@@ -27,7 +27,6 @@
 import java.nio.channels.WritableByteChannel;
 import java.util.concurrent.ThreadLocalRandom;
 
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.Assert;
@@ -57,9 +56,8 @@
 
   @Test
   public void testOffHeap() throws Exception {
-    try (WritableHandle handle =
+    try (WritableMemory mem =
         WritableMemory.allocateDirect((UNSAFE_COPY_THRESHOLD_BYTES * 5) + 10)) {
-      WritableMemory mem = handle.getWritable();
       testWriteTo(mem.region(0, 0));
       testOffHeap(mem, 7);
       testOffHeap(mem, 1023);
@@ -91,6 +89,6 @@
       mem.writeTo(0, mem.getCapacity(), out);
     }
     byte[] result = baos.toByteArray();
-    Assert.assertTrue(mem.equals(Memory.wrap(result)));
+    Assert.assertTrue(mem.equalTo(Memory.wrap(result)));
   }
 }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MurmurHash3v2Test.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MurmurHash3v2Test.java
deleted file mode 100644
index 6949008..0000000
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MurmurHash3v2Test.java
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.datasketches.memory.MurmurHash3v2.hash;
-import static org.testng.Assert.fail;
-
-import org.apache.datasketches.memory.Memory;
-import org.apache.datasketches.memory.MurmurHash3v2;
-import org.apache.datasketches.memory.WritableHandle;
-import org.apache.datasketches.memory.WritableMemory;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-/**
- * Tests the MurmurHash3 against specific, known hash results given known
- * inputs obtained from the public domain C++ version 150.
- *
- * @author Lee Rhodes
- */
-public class MurmurHash3v2Test {
-
-  @Test
-  public void checkByteArrRemainderGT8() { //byte[], remainder > 8
-    String keyStr = "The quick brown fox jumps over the lazy dog";
-    byte[] key = keyStr.getBytes(UTF_8);
-    long[] result = hash(key, 0);
-    //Should be:
-    long h1 = 0xe34bbc7bbc071b6cL;
-    long h2 = 0x7a433ca9c49a9347L;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-  }
-
-  @Test
-  public void checkByteArrChange1bit() { //byte[], change one bit
-    String keyStr = "The quick brown fox jumps over the lazy eog";
-    byte[] key = keyStr.getBytes(UTF_8);
-    long[] result = hash(key, 0);
-    //Should be:
-    long h1 = 0x362108102c62d1c9L;
-    long h2 = 0x3285cd100292b305L;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-  }
-
-  @Test
-  public void checkByteArrRemainderLt8() { //byte[], test a remainder < 8
-    String keyStr = "The quick brown fox jumps over the lazy dogdogdog";
-    byte[] key = keyStr.getBytes(UTF_8);
-    long[] result = hash(key, 0);
-    //Should be;
-    long h1 = 0x9c8205300e612fc4L;
-    long h2 = 0xcbc0af6136aa3df9L;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-  }
-
-  @Test
-  public void checkByteArrReaminderEQ8() { //byte[], test a remainder = 8
-    String keyStr = "The quick brown fox jumps over the lazy1";
-    byte[] key = keyStr.getBytes(UTF_8);
-    long[] result = hash(key, 0);
-    //Should be:
-    long h1 = 0xe3301a827e5cdfe3L;
-    long h2 = 0xbdbf05f8da0f0392L;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-
-  }
-
-  /**
-   * This test should have the exact same output as Test4
-   */
-  @Test
-  public void checkLongArrRemainderEQ8() { //long[], test a remainder = 8
-    String keyStr = "The quick brown fox jumps over the lazy1";
-    long[] key = stringToLongs(keyStr);
-    long[] result = hash(key, 0);
-    //Should be:
-    long h1 = 0xe3301a827e5cdfe3L;
-    long h2 = 0xbdbf05f8da0f0392L;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-
-  }
-
-  /**
-   * This test should have the exact same output as Test4
-   */
-  @Test
-  public void checkIntArrRemainderEQ8() { //int[], test a remainder = 8
-    String keyStr = "The quick brown fox jumps over the lazy1"; //40B
-    int[] key = stringToInts(keyStr);
-    long[] result = hash(key, 0);
-    //Should be:
-    long h1 = 0xe3301a827e5cdfe3L;
-    long h2 = 0xbdbf05f8da0f0392L;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-  }
-
-  @Test
-  public void checkIntArrRemainderEQ0() { //int[], test a remainder = 0
-    String keyStr = "The quick brown fox jumps over t"; //32B
-    int[] key = stringToInts(keyStr);
-    long[] result = hash(key, 0);
-    //Should be:
-    long h1 = 0xdf6af91bb29bdacfL;
-    long h2 = 0x91a341c58df1f3a6L;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-  }
-
-
-  /**
-   * Tests an odd remainder of int[].
-   */
-  @Test
-  public void checkIntArrOddRemainder() { //int[], odd remainder
-    String keyStr = "The quick brown fox jumps over the lazy dog"; //43B
-    int[] key = stringToInts(keyStr);
-    long[] result = hash(key, 0);
-    //Should be:
-    long h1 = 0x1eb232b0087543f5L;
-    long h2 = 0xfc4c1383c3ace40fL;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-  }
-
-
-  /**
-   * Tests an odd remainder of int[].
-   */
-  @Test
-  public void checkCharArrOddRemainder() { //char[], odd remainder
-    String keyStr = "The quick brown fox jumps over the lazy dog.."; //45B
-    char[] key = keyStr.toCharArray();
-    long[] result = hash(key, 0);
-    //Should be:
-    long h1 = 0xca77b498ea9ed953L;
-    long h2 = 0x8b8f8ec3a8f4657eL;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-  }
-
-  /**
-   * Tests an odd remainder of int[].
-   */
-  @Test
-  public void checkCharArrRemainderEQ0() { //char[], remainder of 0
-    String keyStr = "The quick brown fox jumps over the lazy "; //40B
-    char[] key = keyStr.toCharArray();
-    long[] result = hash(key, 0);
-    //Should be:
-    long h1 = 0x51b15e9d0887f9f1L;
-    long h2 = 0x8106d226786511ebL;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-  }
-
-  @Test
-  public void checkByteArrAllOnesZeros() { //byte[], test a ones byte and a zeros byte
-    byte[] key = {
-      0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e,
-      0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65,
-      0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67,
-      (byte) 0xff, 0x64, 0x6f, 0x67, 0x00
-    };
-    long[] result = MurmurHash3v2.hash(key, 0);
-
-    //Should be:
-    long h1 = 0xe88abda785929c9eL;
-    long h2 = 0x96b98587cacc83d6L;
-    Assert.assertEquals(result[0], h1);
-    Assert.assertEquals(result[1], h2);
-  }
-
-  /**
-   * This test demonstrates that the hash of byte[], char[], int[], or long[] will produce the
-   * same hash result if, and only if, all the arrays have the same exact length in bytes, and if
-   * the contents of the values in the arrays have the same byte endianness and overall order.
-   */
-  @Test
-  public void checkCrossTypeHashConsistency() {
-    long[] out;
-    println("Bytes");
-    byte[] bArr = {1,2,3,4,5,6,7,8,   9,10,11,12,13,14,15,16,  17,18,19,20,21,22,23,24};
-    long[] out1 = hash(bArr, 0L);
-    println(longToHexBytes(out1[0]));
-    println(longToHexBytes(out1[1]));
-
-    println("Chars");
-    char[] cArr = {0X0201, 0X0403, 0X0605, 0X0807,   0X0a09, 0X0c0b, 0X0e0d, 0X100f,
-        0X1211, 0X1413, 0X1615, 0X1817};
-    out = hash(cArr, 0L);
-    Assert.assertEquals(out, out1);
-    println(longToHexBytes(out[0]));
-    println(longToHexBytes(out[1]));
-
-    println("Ints");
-    int[] iArr = {0X04030201, 0X08070605,   0X0c0b0a09, 0X100f0e0d,   0X14131211,   0X18171615};
-    out = hash(iArr, 0L);
-    Assert.assertEquals(out, out1);
-    println(longToHexBytes(out[0]));
-    println(longToHexBytes(out[1]));
-
-    println("Longs");
-    long[] lArr = {0X0807060504030201L, 0X100f0e0d0c0b0a09L, 0X1817161514131211L};
-    out = hash(lArr, 0L);
-    Assert.assertEquals(out, out1);
-    println(longToHexBytes(out[0]));
-    println(longToHexBytes(out[1]));
-  }
-
-  @Test
-  public void checkEmptyOrNullExceptions() {
-    try {
-      long[] arr = null; hash(arr, 1L); fail();
-    } catch (final IllegalArgumentException e) { }
-    try {
-      int[] arr = null; hash(arr, 1L); fail();
-    } catch (final IllegalArgumentException e) { }
-    try {
-      char[] arr = null; hash(arr, 1L); fail();
-    } catch (final IllegalArgumentException e) { }
-    try {
-      byte[] arr = null; hash(arr, 1L); fail();
-    } catch (final IllegalArgumentException e) { }
-    try {
-      long[] out = new long[2];
-      String in = null; hash(in, 1L, out); fail();
-    } catch (final IllegalArgumentException e) { }
-    try {
-      long[] out = new long[2];
-      Memory mem = Memory.wrap(new byte[0]);
-      out = hash(mem, 0L, 4L, 1L, out);
-    } catch (final IllegalArgumentException e) { }
-    try (WritableHandle wh = WritableMemory.allocateDirect(8)) {
-      long[] out = new long[2];
-      Memory mem = wh.get();
-      out = hash(mem, 0L, 4L, 1L, out);
-    } catch (Exception ee) {}
-  }
-
-  @Test
-  public void checkHashTails() {
-    long[] out = new long[2];
-    WritableMemory mem = WritableMemory.allocate(32);
-    mem.fill((byte)85);
-
-    for (int i = 16; i <= 32; i++) {
-      out = hash(mem, 0, i, 1L, out);
-    }
-  }
-
-  @Test
-  public void checkSinglePrimitives() {
-    long[] out = new long[2];
-    out = hash(1L, 1L, out);
-    out = hash(0.0, 1L, out);
-    out = hash("123", 1L, out);
-  }
-
-  //Helper methods
-
-  private static long[] stringToLongs(String in) {
-    byte[] bArr = in.getBytes(UTF_8);
-    int inLen = bArr.length;
-    int outLen = (inLen / 8) + (((inLen % 8) != 0) ? 1 : 0);
-    long[] out = new long[outLen];
-
-    for (int i = 0; i < (outLen - 1); i++ ) {
-      for (int j = 0; j < 8; j++ ) {
-        out[i] |= ((bArr[(i * 8) + j] & 0xFFL) << (j * 8));
-      }
-    }
-    int inTail = 8 * (outLen - 1);
-    int rem = inLen - inTail;
-    for (int j = 0; j < rem; j++ ) {
-      out[outLen - 1] |= ((bArr[inTail + j] & 0xFFL) << (j * 8));
-    }
-    return out;
-  }
-
-  private static int[] stringToInts(String in) {
-    byte[] bArr = in.getBytes(UTF_8);
-    int inLen = bArr.length;
-    int outLen = (inLen / 4) + (((inLen % 4) != 0) ? 1 : 0);
-    int[] out = new int[outLen];
-
-    for (int i = 0; i < (outLen - 1); i++ ) {
-      for (int j = 0; j < 4; j++ ) {
-        out[i] |= ((bArr[(i * 4) + j] & 0xFFL) << (j * 8));
-      }
-    }
-    int inTail = 4 * (outLen - 1);
-    int rem = inLen - inTail;
-    for (int j = 0; j < rem; j++ ) {
-      out[outLen - 1] |= ((bArr[inTail + j] & 0xFFL) << (j * 8));
-    }
-    return out;
-  }
-
-  /**
-   * Returns a string of spaced hex bytes in Big-Endian order.
-   * @param v the given long
-   * @return string of spaced hex bytes in Big-Endian order.
-   */
-  private static String longToHexBytes(final long v) {
-    final long mask = 0XFFL;
-    final StringBuilder sb = new StringBuilder();
-    for (int i = 8; i-- > 0; ) {
-      final String s = Long.toHexString((v >>> (i * 8)) & mask);
-      sb.append(zeroPad(s, 2)).append(" ");
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Prepend the given string with zeros. If the given string is equal or greater than the given
-   * field length, it will be returned without modification.
-   * @param s the given string
-   * @param fieldLength desired total field length including the given string
-   * @return the given string prepended with zeros.
-   */
-  private static final String zeroPad(final String s, final int fieldLength) {
-    return characterPad(s, fieldLength, '0', false);
-  }
-
-  /**
-   * Prepend or postpend the given string with the given character to fill the given field length.
-   * If the given string is equal or greater than the given field length, it will be returned
-   * without modification.
-   * @param s the given string
-   * @param fieldLength the desired field length
-   * @param padChar the desired pad character
-   * @param postpend if true append the padCharacters to the end of the string.
-   * @return prepended or postpended given string with the given character to fill the given field
-   * length.
-   */
-  private static final String characterPad(final String s, final int fieldLength, final char padChar,
-      final boolean postpend) {
-    final char[] chArr = s.toCharArray();
-    final int sLen = chArr.length;
-    if (sLen < fieldLength) {
-      final char[] out = new char[fieldLength];
-      final int blanks = fieldLength - sLen;
-
-      if (postpend) {
-        for (int i = 0; i < sLen; i++) {
-          out[i] = chArr[i];
-        }
-        for (int i = sLen; i < fieldLength; i++) {
-          out[i] = padChar;
-        }
-      } else { //prepend
-        for (int i = 0; i < blanks; i++) {
-          out[i] = padChar;
-        }
-        for (int i = blanks; i < fieldLength; i++) {
-          out[i] = chArr[i - blanks];
-        }
-      }
-
-      return String.valueOf(out);
-    }
-    return s;
-  }
-
-  @Test
-  public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
-  }
-
-  /**
-   * @param s value to print
-   */
-  static void println(String s) {
-    //System.out.println(s); //disable here
-  }
-
-}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java
index 0461104..7a60d11 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java
@@ -23,17 +23,17 @@
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
 import org.apache.datasketches.memory.Buffer;
 import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryBoundsException;
 import org.apache.datasketches.memory.ReadOnlyException;
 import org.apache.datasketches.memory.WritableBuffer;
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.WritableMemory;
-import org.testng.Assert;
 import org.testng.annotations.Test;
 
 public class NativeWritableBufferImplTest {
@@ -41,17 +41,14 @@
   //Simple Native direct
 
   @Test
-  public void checkNativeCapacityAndClose() throws Exception {
+  public void checkNativeCapacityAndClose() {
     int memCapacity = 64;
-    WritableHandle wmh = WritableMemory.allocateDirect(memCapacity);
-    WritableMemory wmem = wmh.getWritable();
+    WritableMemory wmem = WritableMemory.allocateDirect(memCapacity);
     WritableBuffer wbuf = wmem.asWritableBuffer();
     assertEquals(wbuf.getCapacity(), memCapacity);
 
-    wmh.close(); //intentional
+    wmem.close(); //intentional
     assertFalse(wbuf.isValid());
-
-    wmh.close(); //intentional, nothing to free
   }
 
   //Simple Heap arrays
@@ -63,16 +60,16 @@
 
     Buffer buf = Memory.wrap(srcArray).asBuffer();
     buf.getBooleanArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
     wbuf.getBooleanArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
-    assertTrue(buf.hasArray());
+    assertTrue(buf.isHeapResource());
   }
 
   @Test
@@ -82,13 +79,13 @@
 
     Buffer buf = Memory.wrap(srcArray).asBuffer();
     buf.getByteArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
     wbuf.getByteArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -100,13 +97,13 @@
 
     Buffer buf = Memory.wrap(srcArray).asBuffer();
     buf.getCharArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
     wbuf.getCharArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -118,13 +115,13 @@
 
     Buffer buf = Memory.wrap(srcArray).asBuffer();
     buf.getShortArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
     wbuf.getShortArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -136,13 +133,13 @@
 
     Buffer buf = Memory.wrap(srcArray).asBuffer();
     buf.getIntArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
     wbuf.getIntArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -154,13 +151,13 @@
 
     Buffer buf = Memory.wrap(srcArray).asBuffer();
     buf.getLongArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
     wbuf.getLongArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -172,13 +169,13 @@
 
     Buffer buf = Memory.wrap(srcArray).asBuffer();
     buf.getFloatArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
     wbuf.getFloatArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -190,50 +187,48 @@
 
     Buffer buf = Memory.wrap(srcArray).asBuffer();
     buf.getDoubleArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
     wbuf.getDoubleArray(dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
 
   @Test
-  public void checkNativeBaseBound() throws Exception {
+  public void checkNativeBaseBound() {
     int memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory wmem = wrh.getWritable();
+    try (WritableMemory wmem = WritableMemory.allocateDirect(memCapacity)) {
       WritableBuffer wbuf = wmem.asWritableBuffer();
-      wbuf.toHexString("Force Assertion Error", memCapacity, 8);
-    } catch (IllegalArgumentException e) {
+      wbuf.toHexString("Bounds Exception", memCapacity, 8); //Bounds Exception
+      fail("Should have thrown MemoryBoundsException");
+    } catch (MemoryBoundsException e) {
       //ok
     }
   }
 
   @Test
-  public void checkNativeSrcArrayBound() throws Exception {
+  public void checkNativeSrcArrayBound() {
     long memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory wmem = wrh.getWritable();
+    try (WritableMemory wmem = WritableMemory.allocateDirect(memCapacity)) {
       WritableBuffer wbuf = wmem.asWritableBuffer();
       byte[] srcArray = { 1, -2, 3, -4 };
-      wbuf.putByteArray(srcArray, 0, 5); //wrong!
-    } catch (IllegalArgumentException e) {
+      wbuf.putByteArray(srcArray, 0, 5); //should be 4!
+      fail("Should have thrown MemoryBoundsException");
+    } catch (MemoryBoundsException e) {
       //pass
     }
   }
 
-
-  @Test(expectedExceptions = IllegalArgumentException.class)
-  public void checkRegionBounds() throws Exception {
+  @Test(expectedExceptions = MemoryBoundsException.class)
+  public void checkRegionBounds() {
     int memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory wmem = wrh.getWritable();
+    try (WritableMemory wmem = WritableMemory.allocateDirect(memCapacity)) {
       WritableBuffer wbuf = wmem.asWritableBuffer();
-      wbuf.writableRegion(1, 64, wbuf.getTypeByteOrder()); //wrong!
+      wbuf.writableRegion(1, 64, wbuf.getByteOrder()); //off by one
     }
   }
 
@@ -243,18 +238,18 @@
     ByteBuffer byteBuf = ByteBuffer.allocate(memCapacity);
     byteBuf.order(ByteOrder.nativeOrder());
 
-    for (int i=0; i<memCapacity; i++) {
+    for (int i = 0; i < memCapacity; i++) {
       byteBuf.put(i, (byte) i);
     }
 
     WritableBuffer wbuf = WritableBuffer.writableWrap(byteBuf);
 
-    for (int i=0; i<memCapacity; i++) {
+    for (int i = 0; i < memCapacity; i++) {
       assertEquals(wbuf.getByte(), byteBuf.get(i));
     }
 
-    assertTrue(wbuf.hasByteBuffer());
-    ByteBuffer byteBuf2 = wbuf.getByteBuffer();
+    assertTrue(wbuf.isByteBufferResource());
+    ByteBuffer byteBuf2 = ((ResourceImpl)wbuf).getByteBuffer();
     assertEquals(byteBuf2, byteBuf);
     //println( mem.toHexString("HeapBB", 0, memCapacity));
   }
@@ -327,13 +322,13 @@
     ByteBuffer byteBuf = ByteBuffer.allocateDirect(memCapacity);
     byteBuf.order(ByteOrder.nativeOrder());
 
-    for (int i=0; i<memCapacity; i++) {
+    for (int i = 0; i < memCapacity; i++) {
       byteBuf.put(i, (byte) i);
     }
 
     Buffer buf = Buffer.wrap(byteBuf);
 
-    for (int i=0; i<memCapacity; i++) {
+    for (int i = 0; i < memCapacity; i++) {
       assertEquals(buf.getByte(), byteBuf.get(i));
     }
 
@@ -341,15 +336,13 @@
   }
 
   @Test
-  public void checkIsDirect() throws Exception {
+  public void checkIsDirect() {
     int memCapacity = 64;
     WritableBuffer mem = WritableMemory.allocate(memCapacity).asWritableBuffer();
-    assertFalse(mem.isDirect());
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem2 = wrh.getWritable();
+    assertFalse(mem.isDirectResource());
+    try (WritableMemory mem2 = WritableMemory.allocateDirect(memCapacity)) {
       WritableBuffer wbuf = mem2.asWritableBuffer();
-      assertTrue(wbuf.isDirect());
-      wrh.close(); //immediate close
+      assertTrue(wbuf.isDirectResource());
     }
   }
 
@@ -370,7 +363,7 @@
 
   @Test
   public void checkGoodBounds() {
-    UnsafeUtil.checkBounds(50, 50, 100);
+    ResourceImpl.checkBounds(50, 50, 100);
   }
 
   @Test
@@ -397,22 +390,17 @@
   }
 
   @Test
-  public void checkCompareToDirect() throws Exception {
+  public void checkCompareToDirect() {
     byte[] arr1 = new byte[] {0, 1, 2, 3};
     byte[] arr2 = new byte[] {0, 1, 2, 4};
     byte[] arr3 = new byte[] {0, 1, 2, 3, 4};
 
-    try (WritableHandle h1 = WritableMemory.allocateDirect(4);
-        WritableHandle h2 = WritableMemory.allocateDirect(4);
-        WritableHandle h3 = WritableMemory.allocateDirect(5))
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(4);
+        WritableMemory mem2 = WritableMemory.allocateDirect(4);
+        WritableMemory mem3 = WritableMemory.allocateDirect(5))
     {
-      WritableMemory mem1 = h1.getWritable();
       mem1.putByteArray(0, arr1, 0, 4);
-
-      WritableMemory mem2 = h2.getWritable();
       mem2.putByteArray(0, arr2, 0, 4);
-
-      WritableMemory mem3 = h3.getWritable();
       mem3.putByteArray(0, arr3, 0, 5);
 
       Buffer buf1 = mem1.asBuffer();
@@ -454,7 +442,7 @@
     for (int i = 0; i < 64; i++) { wmem.putByte(i, (byte)i); }
 
     WritableBuffer wbuf = wmem.asWritableBuffer().writableDuplicate();
-    wbuf.checkValidAndBounds(0, 64);
+    ((ResourceImpl)wbuf).checkValidAndBounds(0, 64);
     for (int i = 0; i < 64; i++) {
       assertEquals(wbuf.getByte(), i);
     }
@@ -468,7 +456,7 @@
       assertEquals(wmem2.getByte(i), i);
     }
     WritableMemory wmem3 = wbuf.asWritableMemory();
-    wmem3.checkValidAndBounds(0, 64);
+    ((ResourceImpl)wmem3).checkValidAndBounds(0, 64);
   }
 
   @Test
@@ -476,10 +464,8 @@
     WritableMemory wmem = WritableMemory.allocate(64);
     WritableMemory reg = wmem.writableRegion(32, 32);
     WritableBuffer buf = reg.asWritableBuffer();
-    assertEquals(buf.getRegionOffset(), 32);
-    assertEquals(buf.getRegionOffset(0), 32);
-    assertEquals(buf.getCumulativeOffset(), 32 + 16);
-    assertEquals(buf.getCumulativeOffset(0), 32 + 16);
+    assertEquals(buf.getTotalOffset(), 32);
+    assertEquals(((ResourceImpl)buf).getCumulativeOffset(0), 32 + 16);
   }
 
   @Test
@@ -509,7 +495,7 @@
       Buffer buf = Buffer.wrap(bb.asReadOnlyBuffer());
       wbuf = (WritableBuffer) buf;
       wmem = wbuf.asWritableMemory();
-      Assert.fail();
+      fail("Should have thrown exception");
     } catch (ReadOnlyException expected) {
       // expected
     }
@@ -527,7 +513,7 @@
       wbuf = (WritableBuffer) buf;
       @SuppressWarnings("unused")
       WritableBuffer wdup2 = wbuf.writableDuplicate();
-      Assert.fail();
+      fail("Should have thrown exception");
     } catch (ReadOnlyException expected) {
       // ignore
     }
@@ -545,7 +531,7 @@
       wbuf = (WritableBuffer) buf;
       @SuppressWarnings("unused")
       WritableBuffer wreg2 = wbuf.writableRegion();
-      Assert.fail();
+      fail("Should have thrown exception");
     } catch (ReadOnlyException expected) {
       // ignore
     }
@@ -556,14 +542,14 @@
     ByteBuffer bb = ByteBuffer.allocate(64);
     WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
     @SuppressWarnings("unused")
-    WritableBuffer wreg = wbuf.writableRegion(0, 1, wbuf.getTypeByteOrder());
+    WritableBuffer wreg = wbuf.writableRegion(0, 1, wbuf.getByteOrder());
 
     try {
       Buffer buf = Buffer.wrap(bb);
       wbuf = (WritableBuffer) buf;
       @SuppressWarnings("unused")
-      WritableBuffer wreg2 = wbuf.writableRegion(0, 1, wbuf.getTypeByteOrder());
-      Assert.fail();
+      WritableBuffer wreg2 = wbuf.writableRegion(0, 1, wbuf.getByteOrder());
+      fail("Should have thrown exception");
     } catch (ReadOnlyException expected) {
       // ignore
     }
@@ -573,7 +559,7 @@
   public void checkZeroBuffer() {
     WritableMemory wmem = WritableMemory.allocate(8);
     WritableBuffer wbuf = wmem.asWritableBuffer();
-    WritableBuffer reg = wbuf.writableRegion(0, 0, wbuf.getTypeByteOrder());
+    WritableBuffer reg = wbuf.writableRegion(0, 0, wbuf.getByteOrder());
     assertEquals(reg.getCapacity(), 0);
   }
 
@@ -587,7 +573,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java
index 8d52250..f8a07e6 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java
@@ -27,9 +27,9 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.Buffer;
 import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryBoundsException;
 import org.apache.datasketches.memory.ReadOnlyException;
 import org.apache.datasketches.memory.WritableBuffer;
 import org.apache.datasketches.memory.WritableMemory;
@@ -40,16 +40,13 @@
   //Simple Native direct
 
   @Test
-  public void checkNativeCapacityAndClose() throws Exception {
+  public void checkNativeCapacityAndClose() {
     int memCapacity = 64;
-    WritableHandle wmh = WritableMemory.allocateDirect(memCapacity);
-    WritableMemory mem = wmh.getWritable();
+    WritableMemory mem = WritableMemory.allocateDirect(memCapacity);
     assertEquals(memCapacity, mem.getCapacity());
 
-    wmh.close(); //intentional
+    mem.close(); //intentional
     assertFalse(mem.isValid());
-
-    wmh.close(); //intentional, nothing to free
   }
 
   //Simple Native arrays
@@ -61,16 +58,16 @@
 
     Memory mem = Memory.wrap(srcArray);
     mem.getBooleanArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableMemory wmem = WritableMemory.writableWrap(srcArray);
     wmem.getBooleanArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
-    assertTrue(mem.hasArray());
+    assertTrue(mem.isHeapResource());
   }
 
   @Test
@@ -80,13 +77,13 @@
 
     Memory mem = Memory.wrap(srcArray);
     mem.getByteArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableMemory wmem = WritableMemory.writableWrap(srcArray);
     wmem.getByteArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -98,13 +95,13 @@
 
     Memory mem = Memory.wrap(srcArray);
     mem.getCharArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableMemory wmem = WritableMemory.writableWrap(srcArray);
     wmem.getCharArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -116,13 +113,13 @@
 
     Memory mem = Memory.wrap(srcArray);
     mem.getShortArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableMemory wmem = WritableMemory.writableWrap(srcArray);
     wmem.getShortArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -134,13 +131,13 @@
 
     Memory mem = Memory.wrap(srcArray);
     mem.getIntArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableMemory wmem = WritableMemory.writableWrap(srcArray);
     wmem.getIntArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -152,13 +149,13 @@
 
     Memory mem = Memory.wrap(srcArray);
     mem.getLongArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableMemory wmem = WritableMemory.writableWrap(srcArray);
     wmem.getLongArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -170,13 +167,13 @@
 
     Memory mem = Memory.wrap(srcArray);
     mem.getFloatArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableMemory wmem = WritableMemory.writableWrap(srcArray);
     wmem.getFloatArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
@@ -188,36 +185,36 @@
 
     Memory mem = Memory.wrap(srcArray);
     mem.getDoubleArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
 
     WritableMemory wmem = WritableMemory.writableWrap(srcArray);
     wmem.getDoubleArray(0, dstArray, 0, 8);
-    for (int i=0; i<8; i++) {
+    for (int i = 0; i < 8; i++) {
       assertEquals(dstArray[i], srcArray[i]);
     }
   }
 
   @Test
-  public void checkNativeBaseBound() throws Exception {
+  public void checkNativeBaseBound() {
     int memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.toHexString("Force Assertion Error", memCapacity, 8);
-    } catch (IllegalArgumentException e) {
+      fail("Should have thrown MemoryBoundsException");
+    } catch (MemoryBoundsException e) { //bounds exception
       //ok
     }
   }
 
   @Test
-  public void checkNativeSrcArrayBound() throws Exception {
+  public void checkNativeSrcArrayBound() {
     long memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       byte[] srcArray = { 1, -2, 3, -4 };
       mem.putByteArray(0L, srcArray, 0, 5);
-    } catch (IllegalArgumentException e) {
+      fail("Should have thrown MemoryBoundsException");
+    } catch (MemoryBoundsException e) {
       //pass
     }
   }
@@ -227,153 +224,138 @@
   @Test(expectedExceptions = IllegalArgumentException.class)
   public void checkDegenerateCopyTo() {
     WritableMemory wmem = WritableMemory.allocate(64);
-    wmem.copyTo(0, wmem, 0, 64);
+    wmem.copyTo(0, wmem, 0, 64); //Attempt to copy a block of memory exactly in-place, should be a bug
   }
 
   @Test
-  public void checkCopyWithinNativeSmall() throws Exception {
+  public void checkCopyWithinNativeSmall() {
     int memCapacity = 64;
-    int half = memCapacity/2;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    int half = memCapacity / 2;
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.clear();
 
-      for (int i=0; i<half; i++) { //fill first half
+      for (int i = 0; i < half; i++) { //fill first half
         mem.putByte(i, (byte) i);
       }
 
       mem.copyTo(0, mem, half, half);
 
-      for (int i=0; i<half; i++) {
-        assertEquals(mem.getByte(i+half), (byte) i);
+      for (int i = 0; i < half; i++) {
+        assertEquals(mem.getByte(i + half), (byte) i);
       }
     }
   }
 
   @Test
-  public void checkCopyWithinNativeLarge() throws Exception {
+  public void checkCopyWithinNativeLarge() {
     int memCapacity = (2 << 20) + 64;
     int memCapLongs = memCapacity / 8;
     int halfBytes = memCapacity / 2;
     int halfLongs = memCapLongs / 2;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.clear();
 
-      for (int i=0; i < halfLongs; i++) {
-        mem.putLong(i*8, i);
+      for (int i = 0; i < halfLongs; i++) {
+        mem.putLong(i * 8, i);
       }
 
       mem.copyTo(0, mem, halfBytes, halfBytes);
 
-      for (int i=0; i < halfLongs; i++) {
-        assertEquals(mem.getLong((i + halfLongs)*8), i);
+      for (int i = 0; i < halfLongs; i++) {
+        assertEquals(mem.getLong((i + halfLongs) * 8), i);
       }
     }
   }
 
   @Test
-  public void checkCopyWithinNativeSrcBound() throws Exception {
+  public void checkCopyWithinNativeSrcBound() {
     int memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.copyTo(32, mem, 32, 33);  //hit source bound check
-      fail("Did Not Catch Assertion Error: source bound");
+      fail("Should have thrown MemoryBoundsException");
     }
-    catch (IllegalArgumentException e) {
+    catch (MemoryBoundsException e) {
       //pass
     }
   }
 
   @Test
-  public void checkCopyWithinNativeDstBound() throws Exception {
+  public void checkCopyWithinNativeDstBound() {
     int memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.copyTo(0, mem, 32, 33);  //hit dst bound check
-      fail("Did Not Catch Assertion Error: dst bound");
+      fail("Should have thrown MemoryBoundsException");
     }
-    catch (IllegalArgumentException e) {
+    catch (MemoryBoundsException e) {
       //pass
     }
   }
 
   @Test
-  public void checkCopyCrossNativeSmall() throws Exception {
+  public void checkCopyCrossNativeSmall() {
     int memCapacity = 64;
 
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity);
-        WritableHandle wrh2 = WritableMemory.allocateDirect(memCapacity))
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity);
+        WritableMemory mem2 = WritableMemory.allocateDirect(memCapacity))
     {
-      WritableMemory mem1 = wrh1.getWritable();
-      WritableMemory mem2 = wrh2.getWritable();
-
-      for (int i=0; i < memCapacity; i++) {
+      for (int i = 0; i < memCapacity; i++) {
         mem1.putByte(i, (byte) i);
       }
       mem2.clear();
       mem1.copyTo(0, mem2, 0, memCapacity);
 
-      for (int i=0; i<memCapacity; i++) {
+      for (int i = 0; i < memCapacity; i++) {
         assertEquals(mem2.getByte(i), (byte) i);
       }
-      wrh1.close();
-      wrh2.close();
     }
   }
 
   @Test
-  public void checkCopyCrossNativeLarge() throws Exception {
-    int memCapacity = (2<<20) + 64;
+  public void checkCopyCrossNativeLarge() {
+    int memCapacity = (2 << 20) + 64;
     int memCapLongs = memCapacity / 8;
 
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity);
-        WritableHandle wrh2 = WritableMemory.allocateDirect(memCapacity))
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity);
+        WritableMemory mem2 = WritableMemory.allocateDirect(memCapacity))
     {
-      WritableMemory mem1 = wrh1.getWritable();
-      WritableMemory mem2 = wrh2.getWritable();
-
-      for (int i=0; i < memCapLongs; i++) {
-        mem1.putLong(i*8, i);
+      for (int i = 0; i < memCapLongs; i++) {
+        mem1.putLong(i * 8, i);
       }
       mem2.clear();
 
       mem1.copyTo(0, mem2, 0, memCapacity);
 
-      for (int i=0; i<memCapLongs; i++) {
-        assertEquals(mem2.getLong(i*8), i);
+      for (int i = 0; i < memCapLongs; i++) {
+        assertEquals(mem2.getLong(i * 8), i);
       }
     }
   }
 
   @Test
-  public void checkCopyCrossNativeAndByteArray() throws Exception {
+  public void checkCopyCrossNativeAndByteArray() {
     int memCapacity = 64;
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem1 = wrh1.getWritable();
-
-      for (int i= 0; i < mem1.getCapacity(); i++) {
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity)) {
+      for (int i = 0; i < mem1.getCapacity(); i++) {
         mem1.putByte(i, (byte) i);
       }
 
       WritableMemory mem2 = WritableMemory.allocate(memCapacity);
       mem1.copyTo(8, mem2, 16, 16);
 
-      for (int i=0; i<16; i++) {
-        assertEquals(mem1.getByte(8+i), mem2.getByte(16+i));
+      for (int i = 0; i < 16; i++) {
+        assertEquals(mem1.getByte(8 + i), mem2.getByte(16 + i));
       }
       //println(mem2.toHexString("Mem2", 0, (int)mem2.getCapacity()));
     }
   }
 
   @Test
-  public void checkCopyCrossRegionsSameNative() throws Exception {
+  public void checkCopyCrossRegionsSameNative() {
     int memCapacity = 128;
 
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem1 = wrh1.getWritable();
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity)) {
 
-      for (int i= 0; i < mem1.getCapacity(); i++) {
+      for (int i = 0; i < mem1.getCapacity(); i++) {
         mem1.putByte(i, (byte) i);
       }
       //println(mem1.toHexString("Mem1", 0, (int)mem1.getCapacity()));
@@ -385,21 +367,20 @@
       //println(reg2.toHexString("Reg2", 0, (int)reg2.getCapacity()));
       reg1.copyTo(0, reg2, 0, 16);
 
-      for (int i=0; i<16; i++) {
+      for (int i = 0; i < 16; i++) {
         assertEquals(reg1.getByte(i), reg2.getByte(i));
-        assertEquals(mem1.getByte(8+i), mem1.getByte(24+i));
+        assertEquals(mem1.getByte(8 + i), mem1.getByte(24 + i));
       }
       //println(mem1.toHexString("Mem1", 0, (int)mem1.getCapacity()));
     }
   }
 
   @Test
-  public void checkCopyCrossNativeArrayAndHierarchicalRegions() throws Exception {
+  public void checkCopyCrossNativeArrayAndHierarchicalRegions() {
     int memCapacity = 64;
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem1 = wrh1.getWritable();
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity)) {
 
-      for (int i= 0; i < mem1.getCapacity(); i++) { //fill with numbers
+      for (int i = 0; i < mem1.getCapacity(); i++) { //fill with numbers
         mem1.putByte(i, (byte) i);
       }
       //println(mem1.toHexString("Mem1", 0, (int)mem1.getCapacity()));
@@ -420,14 +401,12 @@
         assertEquals(mem2.getByte(i), j);
       }
     }
-
   }
 
-  @Test(expectedExceptions = IllegalArgumentException.class)
-  public void checkRegionBounds() throws Exception {
+  @Test(expectedExceptions = MemoryBoundsException.class)
+  public void checkRegionBounds() {
     int memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.writableRegion(1, 64);
     }
   }
@@ -438,18 +417,18 @@
     ByteBuffer byteBuf = ByteBuffer.allocate(memCapacity);
     byteBuf.order(ByteOrder.nativeOrder());
 
-    for (int i=0; i<memCapacity; i++) {
+    for (int i = 0; i < memCapacity; i++) {
       byteBuf.put(i, (byte) i);
     }
 
     WritableMemory wmem = WritableMemory.writableWrap(byteBuf);
 
-    for (int i=0; i<memCapacity; i++) {
+    for (int i = 0; i < memCapacity; i++) {
       assertEquals(wmem.getByte(i), byteBuf.get(i));
     }
 
-    assertTrue(wmem.hasByteBuffer());
-    ByteBuffer byteBuf2 = wmem.getByteBuffer();
+    assertTrue(wmem.isByteBufferResource());
+    ByteBuffer byteBuf2 = ((ResourceImpl)wmem).getByteBuffer();
     assertEquals(byteBuf2, byteBuf);
     //println( mem.toHexString("HeapBB", 0, memCapacity));
   }
@@ -520,13 +499,13 @@
     ByteBuffer byteBuf = ByteBuffer.allocateDirect(memCapacity);
     byteBuf.order(ByteOrder.nativeOrder());
 
-    for (int i=0; i<memCapacity; i++) {
+    for (int i = 0; i < memCapacity; i++) {
       byteBuf.put(i, (byte) i);
     }
 
     Memory mem = Memory.wrap(byteBuf);
 
-    for (int i=0; i<memCapacity; i++) {
+    for (int i = 0; i < memCapacity; i++) {
       assertEquals(mem.getByte(i), byteBuf.get(i));
     }
 
@@ -534,14 +513,12 @@
   }
 
   @Test
-  public void checkIsDirect() throws Exception {
+  public void checkIsDirect() {
     int memCapacity = 64;
     WritableMemory mem = WritableMemory.allocate(memCapacity);
-    assertFalse(mem.isDirect());
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      mem = wrh.getWritable();
-      assertTrue(mem.isDirect());
-      wrh.close();
+    assertFalse(mem.isDirectResource());
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity)) {
+      assertTrue(mem1.isDirectResource());
     }
   }
 
@@ -562,7 +539,7 @@
 
   @Test
   public void checkGoodBounds() {
-    UnsafeUtil.checkBounds(50, 50, 100);
+    ResourceImpl.checkBounds(50, 50, 100);
   }
 
   @Test
@@ -591,26 +568,21 @@
     assertEquals(comp, 0);
     comp = mem3.compareTo(0, 4, mem4, 1, 4);
     assertEquals(comp, -1);
-    mem3.checkValidAndBounds(0, 5);
+    ((ResourceImpl)mem3).checkValidAndBounds(0, 5);
   }
 
   @Test
-  public void checkCompareToDirect() throws Exception {
+  public void checkCompareToDirect() {
     byte[] arr1 = new byte[] {0, 1, 2, 3};
     byte[] arr2 = new byte[] {0, 1, 2, 4};
     byte[] arr3 = new byte[] {0, 1, 2, 3, 4};
 
-    try (WritableHandle h1 = WritableMemory.allocateDirect(4);
-        WritableHandle h2 = WritableMemory.allocateDirect(4);
-        WritableHandle h3 = WritableMemory.allocateDirect(5))
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(4);
+        WritableMemory mem2 = WritableMemory.allocateDirect(4);
+        WritableMemory mem3 = WritableMemory.allocateDirect(5))
     {
-      WritableMemory mem1 = h1.getWritable();
       mem1.putByteArray(0, arr1, 0, 4);
-
-      WritableMemory mem2 = h2.getWritable();
       mem2.putByteArray(0, arr2, 0, 4);
-
-      WritableMemory mem3 = h3.getWritable();
       mem3.putByteArray(0, arr3, 0, 5);
 
       int comp = mem1.compareTo(0, 3, mem2, 0, 3);
@@ -654,10 +626,9 @@
   public void checkCumAndRegionOffset() {
     WritableMemory wmem = WritableMemory.allocate(64);
     WritableMemory reg = wmem.writableRegion(32, 32);
-    assertEquals(reg.getRegionOffset(), 32);
-    assertEquals(reg.getRegionOffset(0), 32);
-    assertEquals(reg.getCumulativeOffset(), 32 + 16);
-    assertEquals(reg.getCumulativeOffset(0), 32 + 16);
+    assertEquals(reg.getTotalOffset(), 32);
+    assertEquals(((ResourceImpl)reg).getCumulativeOffset(0), 32 + 16);
+
   }
 
   @Test
@@ -710,7 +681,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NioBitsTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NioBitsTest.java
deleted file mode 100644
index 8ed5916..0000000
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NioBitsTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.datasketches.memory.internal;
-
-import static org.testng.Assert.assertEquals;
-
-import org.testng.annotations.Test;
-
-/**
- * @author Lee Rhodes
- */
-public class NioBitsTest {
-
-  @Test
-  public void checkVMParams() {
-    println("Max MemoryImpl: " + NioBits.getMaxDirectByteBufferMemory());
-    println("Page Aligned: " + NioBits.isPageAligned());
-    println("Page Size: " + NioBits.pageSize());
-  }
-
-  @Test
-  public void checkGetAtomicFields() {
-    //testing this beyond 2GB may not work on JVMs < 8GB.
-    //This should be checked manually
-   // long cap = 1024L + Integer.MAX_VALUE;
-    long cap = 1L << 10;
-    printStats();
-    NioBits.reserveMemory(cap, cap);
-    printStats();
-    NioBits. unreserveMemory(cap, cap);
-    printStats();
-  }
-
-  @Test
-  public void checkPageCount() {
-    assertEquals(NioBits.pageCount(0), 0);
-    assertEquals(NioBits.pageCount(1), 1);
-  }
-
-  private static void printStats() {
-    long count = NioBits.getDirectAllocationsCount();
-    long resMem = NioBits.getReservedMemory();
-    long totCap = NioBits.getTotalCapacity();
-    long maxDBBmem = NioBits.getMaxDirectByteBufferMemory();
-    String s = String.format("%,10d\t%,15d\t%,15d\t%,15d", count, resMem, totCap, maxDBBmem);
-    println(s);
-  }
-
-  @Test
-  public void printlnTest() {
-    println("PRINTING: " + this.getClass().getName());
-  }
-
-  /**
-   * @param s value to print
-   */
-  static void println(final String s) {
-    //System.out.println(s); //disable here
-  }
-
-}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java
index 57d481a..d7f0421 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java
@@ -239,10 +239,10 @@
     WritableMemory wmem = WritableMemory.writableWrap(bArr, ByteOrder.BIG_ENDIAN);
     WritableBuffer wbuf = wmem.asWritableBuffer();
     WritableBuffer wdup = wbuf.writableDuplicate();
-    assertEquals(wdup.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(wdup.getByteOrder(), ByteOrder.BIG_ENDIAN);
 
     WritableBuffer wreg = wbuf.writableRegion();
-    assertEquals(wreg.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(wreg.getByteOrder(), ByteOrder.BIG_ENDIAN);
   }
 
   @Test
@@ -251,10 +251,10 @@
     WritableMemory wmem = WritableMemory.writableWrap(bArr, ByteOrder.BIG_ENDIAN);
     Buffer buf = wmem.asBuffer();
     Buffer dup = buf.duplicate();
-    assertEquals(dup.getTypeByteOrder(), ByteOrder.LITTLE_ENDIAN);
+    assertEquals(dup.getByteOrder(), ByteOrder.LITTLE_ENDIAN);
 
     Buffer reg = buf.region();
-    assertEquals(reg.getTypeByteOrder(), ByteOrder.LITTLE_ENDIAN);
+    assertEquals(reg.getByteOrder(), ByteOrder.LITTLE_ENDIAN);
   }
 
 }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java
index c6bd5d0..26f101d 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java
@@ -165,47 +165,11 @@
     assertEquals(arr2, arr1);
   }
 
-  //check Atomic Write Methods
-
-
-  @Test
-  public void testGetAndAddLong() {
-    wmem.getAndAddLong(0, 1L);
-    try {
-      wmem.getAndAddLong(1, 1L);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
-  }
-
-  @Test
-  public void testGetAndSetLong() {
-    wmem.getAndSetLong(0, 1L);
-    try {
-      wmem.getAndSetLong(1, 1L);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
-  }
-
-  @Test
-  public void testCompareAndSwapLong() {
-    wmem.compareAndSwapLong(0, 0L, 1L);
-    try {
-      wmem.compareAndSwapLong(1, 0L, 1L);
-      throw new RuntimeException("Expected AssertionError");
-    } catch (final AssertionError expected) {
-      // ignore
-    }
-  }
-
   //check Region
   @Test
   public void checkRegion() {
     WritableMemory wreg = wmem.writableRegion(0, wmem.getCapacity());
-    assertEquals(wreg.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(wreg.getByteOrder(), ByteOrder.BIG_ENDIAN);
   }
 
   @Test
@@ -213,7 +177,7 @@
     byte[] bArr1 = new byte[0];
     WritableMemory wmem1 = WritableMemory.writableWrap(bArr1, ByteOrder.BIG_ENDIAN);
     Memory reg = wmem1.region(0, wmem1.getCapacity());
-    assertEquals(reg.getTypeByteOrder(), ByteOrder.LITTLE_ENDIAN);
+    assertEquals(reg.getByteOrder(), ByteOrder.LITTLE_ENDIAN);
   }
 
 }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseStateTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ResourceTest.java
similarity index 84%
rename from datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseStateTest.java
rename to datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ResourceTest.java
index 430dfa1..f63cad4 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseStateTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ResourceTest.java
@@ -33,7 +33,7 @@
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
-public class BaseStateTest {
+public class ResourceTest {
 
   @Test
   public void checkPrimOffset() {
@@ -56,9 +56,11 @@
 
   @Test
   public void checkNotEqualTo() {
-    byte[] arr = new byte[8];
-    Memory mem = Memory.wrap(arr);
-    assertFalse(mem.equalTo(0, arr, 0, 8));
+    byte[] arr1 = {1,2,3,4,5,6,7,8};
+    Memory mem1 = Memory.wrap(arr1);
+    byte[] arr2 = {1,2,3,4,5,6,7,9};
+    Memory mem2 = Memory.wrap(arr2);
+    assertFalse(mem1.equalTo(mem2));
   }
 
   //StepBoolean checks
@@ -85,13 +87,6 @@
   }
 
   @Test
-  public void checkGetNativeBaseOffset_Heap() throws Exception {
-    WritableMemory wmem = WritableMemory.allocate(8); //heap
-    final long offset = ((BaseStateImpl)wmem).getNativeBaseOffset();
-    assertEquals(offset, 0L);
-  }
-
-  @Test
   public void checkIsByteOrderCompatible() {
     WritableMemory wmem = WritableMemory.allocate(8);
     assertTrue(wmem.isByteOrderCompatible(ByteOrder.nativeOrder()));
@@ -105,11 +100,11 @@
 
   @Test
   public void checkIsNativeByteOrder() {
-    assertTrue(BaseStateImpl.isNativeByteOrder(ByteOrder.nativeOrder()));
+    assertTrue(Util.isNativeByteOrder(ByteOrder.nativeOrder()));
     try {
-      BaseStateImpl.isNativeByteOrder(null);
+      Util.isNativeByteOrder(null);
       fail();
-    } catch (final IllegalArgumentException e) {}
+    } catch (final IllegalArgumentException e) { }
   }
 
   @Test
@@ -122,14 +117,14 @@
   @Test
   public void checkTypeDecode() {
     for (int i = 0; i < 128; i++) {
-      BaseStateImpl.typeDecode(i);
+      ResourceImpl.typeDecode(i);
     }
   }
 
   /********************/
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/SpecificLeafTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/SpecificLeafTest.java
index 87f7e35..250d0a5 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/SpecificLeafTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/SpecificLeafTest.java
@@ -29,8 +29,6 @@
 
 import org.apache.datasketches.memory.Buffer;
 import org.apache.datasketches.memory.Memory;
-import org.apache.datasketches.memory.WritableHandle;
-import org.apache.datasketches.memory.WritableMapHandle;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
@@ -40,13 +38,16 @@
 public class SpecificLeafTest {
 
   @Test
-  public void checkByteBufferLeafs() {
+  public void checkByteBufferLeaves() {
     int bytes = 128;
     ByteBuffer bb = ByteBuffer.allocate(bytes);
     bb.order(ByteOrder.nativeOrder());
 
     Memory mem = Memory.wrap(bb).region(0, bytes, ByteOrder.nativeOrder());
-    assertTrue(((BaseStateImpl)mem).isBBType());
+    ResourceImpl bsi = (ResourceImpl)mem;
+    int typeId = bsi.getTypeId();
+    assertTrue(bsi.isByteBufferResource());
+    assertTrue(bsi.isNativeOrder(typeId));
     assertTrue(mem.isReadOnly());
     checkCrossLeafTypeIds(mem);
     Buffer buf = mem.asBuffer().region(0, bytes, ByteOrder.nativeOrder());
@@ -56,19 +57,18 @@
     Buffer buf2 = mem2.asBuffer().region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
     Buffer buf3 = buf2.duplicate();
 
-    assertTrue(((BaseStateImpl)mem).isRegionType());
-    assertTrue(((BaseStateImpl)mem2).isRegionType());
-    assertTrue(((BaseStateImpl)buf).isRegionType());
-    assertTrue(((BaseStateImpl)buf2).isRegionType());
-    assertTrue(((BaseStateImpl)buf3).isDuplicateType());
+    assertTrue(((ResourceImpl)mem).isRegionView());
+    assertTrue(((ResourceImpl)mem2).isRegionView());
+    assertTrue(((ResourceImpl)buf).isRegionView());
+    assertTrue(((ResourceImpl)buf2).isRegionView());
+    assertTrue(((ResourceImpl)buf3).isDuplicateBufferView());
   }
 
   @Test
-  public void checkDirectLeafs() throws Exception {
+  public void checkDirectLeaves()  {
     int bytes = 128;
-    try (WritableHandle h = WritableMemory.allocateDirect(bytes)) {
-      WritableMemory wmem = h.getWritable(); //native mem
-      assertTrue(((BaseStateImpl)wmem).isDirectType());
+    try (WritableMemory wmem = WritableMemory.allocateDirect(bytes)) {
+      assertTrue(((ResourceImpl)wmem).isDirectResource());
       assertFalse(wmem.isReadOnly());
       checkCrossLeafTypeIds(wmem);
       WritableMemory nnwmem = wmem.writableRegion(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
@@ -81,16 +81,42 @@
       Buffer buf2 = mem2.asBuffer().region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
       Buffer buf3 = buf2.duplicate();
 
-      assertTrue(((BaseStateImpl)mem).isRegionType());
-      assertTrue(((BaseStateImpl)mem2).isRegionType());
-      assertTrue(((BaseStateImpl)buf).isRegionType());
-      assertTrue(((BaseStateImpl)buf2).isRegionType());
-      assertTrue(((BaseStateImpl)buf3).isDuplicateType());
+      assertTrue(((ResourceImpl)mem).isRegionView());
+      assertTrue(((ResourceImpl)mem2).isRegionView());
+      assertTrue(((ResourceImpl)buf).isRegionView());
+      assertTrue(((ResourceImpl)buf2).isRegionView());
+      assertTrue(((ResourceImpl)buf3).isDuplicateBufferView());
     }
   }
 
   @Test
-  public void checkMapLeafs() throws Exception {
+  public void checkHeapLeaves() {
+    int bytes = 128;
+    Memory mem = Memory.wrap(new byte[bytes]);
+    ResourceImpl bsi = (ResourceImpl)mem;
+    assertTrue(bsi.isHeapResource());
+    assertTrue(bsi.isReadOnly());
+    checkCrossLeafTypeIds(mem);
+    Memory nnreg = mem.region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
+
+    Memory reg = mem.region(0, bytes, ByteOrder.nativeOrder());
+    Buffer buf = reg.asBuffer().region(0, bytes, ByteOrder.nativeOrder());
+    Buffer buf4 = buf.duplicate();
+
+    Memory reg2 = nnreg.region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
+    Buffer buf2 = reg2.asBuffer().region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
+    Buffer buf3 = buf2.duplicate();
+
+    assertFalse(((ResourceImpl)mem).isRegionView());
+    assertTrue(((ResourceImpl)reg2).isRegionView());
+    assertTrue(((ResourceImpl)buf).isRegionView());
+    assertTrue(((ResourceImpl)buf2).isRegionView());
+    assertTrue(((ResourceImpl)buf3).isDuplicateBufferView());
+    assertTrue(((ResourceImpl)buf4).isDuplicateBufferView());
+  }
+
+  @Test
+  public void checkMapLeaves() throws IOException {
     File file = new File("TestFile2.bin");
     if (file.exists()) {
       try {
@@ -106,9 +132,8 @@
 
     final long bytes = 128;
 
-    try (WritableMapHandle h = WritableMemory.writableMap(file, 0L, bytes, ByteOrder.nativeOrder())) {
-      WritableMemory mem = h.getWritable(); //native mem
-      assertTrue(((BaseStateImpl)mem).isMapType());
+    try (WritableMemory mem = WritableMemory.writableMap(file, 0L, bytes, ByteOrder.nativeOrder())) {
+      assertTrue(((ResourceImpl)mem).isMemoryMappedResource());
       assertFalse(mem.isReadOnly());
       checkCrossLeafTypeIds(mem);
       Memory nnreg = mem.region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
@@ -121,73 +146,47 @@
       Buffer buf2 = reg2.asBuffer().region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
       Buffer buf3 = buf2.duplicate();
 
-      assertTrue(((BaseStateImpl)reg).isRegionType());
-      assertTrue(((BaseStateImpl)reg2).isRegionType());
-      assertTrue(((BaseStateImpl)buf).isRegionType());
-      assertTrue(((BaseStateImpl)buf2).isRegionType());
-      assertTrue(((BaseStateImpl)buf3).isDuplicateType());
-      assertTrue(((BaseStateImpl)buf4).isDuplicateType());
+      assertTrue(((ResourceImpl)reg).isRegionView());
+      assertTrue(((ResourceImpl)reg2).isRegionView());
+      assertTrue(((ResourceImpl)buf).isRegionView());
+      assertTrue(((ResourceImpl)buf2).isRegionView());
+      assertTrue(((ResourceImpl)buf3).isDuplicateBufferView());
+      assertTrue(((ResourceImpl)buf4).isDuplicateBufferView());
     }
   }
 
-  @Test
-  public void checkHeapLeafs() {
-    int bytes = 128;
-    Memory mem = Memory.wrap(new byte[bytes]);
-    assertTrue(((BaseStateImpl)mem).isHeapType());
-    assertTrue(((BaseStateImpl)mem).isReadOnlyType());
-    checkCrossLeafTypeIds(mem);
-    Memory nnreg = mem.region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
-
-    Memory reg = mem.region(0, bytes, ByteOrder.nativeOrder());
-    Buffer buf = reg.asBuffer().region(0, bytes, ByteOrder.nativeOrder());
-    Buffer buf4 = buf.duplicate();
-
-    Memory reg2 = nnreg.region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
-    Buffer buf2 = reg2.asBuffer().region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
-    Buffer buf3 = buf2.duplicate();
-
-    assertFalse(((BaseStateImpl)mem).isRegionType());
-    assertTrue(((BaseStateImpl)reg2).isRegionType());
-    assertTrue(((BaseStateImpl)buf).isRegionType());
-    assertTrue(((BaseStateImpl)buf2).isRegionType());
-    assertTrue(((BaseStateImpl)buf3).isDuplicateType());
-    assertTrue(((BaseStateImpl)buf4).isDuplicateType());
-  }
-
   private static void checkCrossLeafTypeIds(Memory mem) {
     Memory reg1 = mem.region(0, mem.getCapacity());
-    assertTrue(((BaseStateImpl)reg1).isRegionType());
-
+    assertTrue(((ResourceImpl)reg1).isRegionView());
     Buffer buf1 = reg1.asBuffer();
-    assertTrue(((BaseStateImpl)buf1).isRegionType());
-    assertTrue(((BaseStateImpl)buf1).isBufferType());
+    assertTrue(((ResourceImpl)buf1).isRegionView());
+    assertTrue(((ResourceImpl)buf1).isBufferApi(((ResourceImpl)buf1).getTypeId()));
     assertTrue(buf1.isReadOnly());
 
     Buffer buf2 = buf1.duplicate();
-    assertTrue(((BaseStateImpl)buf2).isRegionType());
-    assertTrue(((BaseStateImpl)buf2).isBufferType());
-    assertTrue(((BaseStateImpl)buf2).isDuplicateType());
+    assertTrue(((ResourceImpl)buf2).isRegionView());
+    assertTrue(((ResourceImpl)buf2).isBufferApi(((ResourceImpl)buf2).getTypeId()));
+    assertTrue(((ResourceImpl)buf2).isDuplicateBufferView());
     assertTrue(buf2.isReadOnly());
 
     Memory mem2 = buf1.asMemory(); //
-    assertTrue(((BaseStateImpl)mem2).isRegionType());
-    assertFalse(((BaseStateImpl)mem2).isBufferType());
-    assertFalse(((BaseStateImpl)mem2).isDuplicateType());
+    assertTrue(((ResourceImpl)mem2).isRegionView());
+    assertFalse(((ResourceImpl)mem2).isBufferApi(((ResourceImpl)mem2).getTypeId()));
+    assertFalse(((ResourceImpl)mem2).isDuplicateBufferView());
     assertTrue(mem2.isReadOnly());
 
     Buffer buf3 = buf1.duplicate(Util.NON_NATIVE_BYTE_ORDER);
-    assertTrue(((BaseStateImpl)buf3).isRegionType());
-    assertTrue(((BaseStateImpl)buf3).isBufferType());
-    assertTrue(((BaseStateImpl)buf3).isDuplicateType());
-    assertTrue(((BaseStateImpl)buf3).isNonNativeType());
+    assertTrue(((ResourceImpl)buf3).isRegionView());
+    assertTrue(((ResourceImpl)buf3).isBufferApi(((ResourceImpl)buf3).getTypeId()));
+    assertTrue(((ResourceImpl)buf3).isDuplicateBufferView());
+    assertTrue(((ResourceImpl)buf3).isNonNativeOrder());
     assertTrue(buf3.isReadOnly());
 
     Memory mem3 = buf3.asMemory();
-    assertTrue(((BaseStateImpl)mem3).isRegionType());
-    assertFalse(((BaseStateImpl)mem3).isBufferType());
-    assertTrue(((BaseStateImpl)mem3).isDuplicateType());
-    assertTrue(((BaseStateImpl)mem3).isNonNativeType());
+    assertTrue(((ResourceImpl)mem3).isRegionView());
+    assertFalse(((ResourceImpl)mem3).isBufferApi(((ResourceImpl)mem3).getTypeId()));
+    assertTrue(((ResourceImpl)mem3).isDuplicateBufferView());
+    assertTrue(((ResourceImpl)mem3).isNonNativeOrder());
     assertTrue(mem3.isReadOnly());
   }
 
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ThreadTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ThreadTest.java
new file mode 100644
index 0000000..89852bd
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ThreadTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.Util.getResourceFile;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.File;
+
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class ThreadTest {
+
+  File file;
+  Memory mem;
+  WritableMemory wmem;
+  Thread altThread;
+
+  @BeforeClass
+  public void prepareFileAndMemory() {
+    UtilTest.setGettysburgAddressFileToReadOnly();
+    file = getResourceFile("GettysburgAddress.txt");
+    assertTrue(AllocateDirectWritableMap.isFileReadOnly(file));
+  }
+
+  void initMap() {
+    mem = Memory.map(file); assertTrue(mem.isValid());
+  }
+
+  void initDirectMem() {
+    wmem = WritableMemory.allocateDirect(1024); assertTrue(wmem.isValid());
+  }
+
+  Runnable tryMapClose = () -> {
+    try { mem.close(); fail(); }
+    catch (IllegalStateException expected) { }
+  };
+
+  Runnable tryDirectClose = () -> {
+    try { wmem.close(); fail(); }
+    catch (IllegalStateException expected) { }
+  };
+
+  @Test
+  public void runTests() {
+    initMap();
+    altThread = new Thread(tryMapClose, "altThread"); altThread.start();
+    mem.close();
+    initDirectMem();
+    altThread = new Thread(tryDirectClose, "altThread"); altThread.start();
+    wmem.close();
+  }
+
+}
+
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UnsafeUtilTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UnsafeUtilTest.java
index baaf90a..b2ff418 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UnsafeUtilTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UnsafeUtilTest.java
@@ -28,14 +28,12 @@
 
 import org.testng.annotations.Test;
 
-
 /**
  * @author Lee Rhodes
  */
 public class UnsafeUtilTest {
   long testField = 1; //Do not remove & cannot be static. Used in reflection check.
 
-
   @Test
   public void checkJdkString() {
     String jdkVer;
@@ -138,7 +136,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Utf8Test.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Utf8Test.java
index 762efe3..e59a6ac 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Utf8Test.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Utf8Test.java
@@ -29,6 +29,7 @@
 import java.util.List;
 
 import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryBoundsException;
 import org.apache.datasketches.memory.Utf8CodingException;
 import org.apache.datasketches.memory.WritableMemory;
 import org.apache.datasketches.memory.internal.Util.RandomCodePoints;
@@ -40,9 +41,9 @@
  * Adapted version of
  * https://github.com/protocolbuffers/protobuf/blob/master/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java
  *
- * Copyright 2008 Google Inc.  All rights reserved.
+ * <pre>Copyright 2008 Google Inc.  All rights reserved.
  * https://developers.google.com/protocol-buffers/
- * See LICENSE.
+ * See LICENSE.</pre>
  */
 public class Utf8Test {
 
@@ -141,7 +142,7 @@
     for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
       ByteString bs = ByteString.copyFrom(new byte[] {(byte) i });
       if (!bs.isValidUtf8()) { //from -128 to -1
-        assertInvalid(bs.toByteArray());
+        checkInvalidBytes(bs.toByteArray());
       } else {
         valid++; //from 0 to 127
       }
@@ -156,7 +157,7 @@
       for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) {
         ByteString bs = ByteString.copyFrom(new byte[]{(byte) i, (byte) j});
         if (!bs.isValidUtf8()) {
-          assertInvalid(bs.toByteArray());
+          checkInvalidBytes(bs.toByteArray());
         } else {
           valid++;
         }
@@ -179,7 +180,7 @@
             byte[] bytes = new byte[]{(byte) i, (byte) j, (byte) k};
             ByteString bs = ByteString.copyFrom(bytes);
             if (!bs.isValidUtf8()) {
-              assertInvalid(bytes);
+              checkInvalidBytes(bytes);
             } else {
               valid++;
             }
@@ -253,12 +254,12 @@
   @Test
   public void testInvalid_4BytesSamples() {
     // Bad trailing bytes
-    assertInvalid(0xF0, 0xA4, 0xAD, 0x7F);
-    assertInvalid(0xF0, 0xA4, 0xAD, 0xC0);
+    checkInvalidInts(0xF0, 0xA4, 0xAD, 0x7F);
+    checkInvalidInts(0xF0, 0xA4, 0xAD, 0xC0);
 
     // Special cases for byte2
-    assertInvalid(0xF0, 0x8F, 0xAD, 0xA2);
-    assertInvalid(0xF4, 0x90, 0xAD, 0xA2);
+    checkInvalidInts(0xF0, 0x8F, 0xAD, 0xA2);
+    checkInvalidInts(0xF4, 0x90, 0xAD, 0xA2);
   }
 
   @Test
@@ -324,41 +325,41 @@
 
   @Test
   public void testOverlong() {
-    assertInvalid(0xc0, 0xaf);
-    assertInvalid(0xe0, 0x80, 0xaf);
-    assertInvalid(0xf0, 0x80, 0x80, 0xaf);
+    checkInvalidInts(0xc0, 0xaf);
+    checkInvalidInts(0xe0, 0x80, 0xaf);
+    checkInvalidInts(0xf0, 0x80, 0x80, 0xaf);
 
     // Max overlong
-    assertInvalid(0xc1, 0xbf);
-    assertInvalid(0xe0, 0x9f, 0xbf);
-    assertInvalid(0xf0 ,0x8f, 0xbf, 0xbf);
+    checkInvalidInts(0xc1, 0xbf);
+    checkInvalidInts(0xe0, 0x9f, 0xbf);
+    checkInvalidInts(0xf0 ,0x8f, 0xbf, 0xbf);
 
     // null overlong
-    assertInvalid(0xc0, 0x80);
-    assertInvalid(0xe0, 0x80, 0x80);
-    assertInvalid(0xf0, 0x80, 0x80, 0x80);
+    checkInvalidInts(0xc0, 0x80);
+    checkInvalidInts(0xe0, 0x80, 0x80);
+    checkInvalidInts(0xf0, 0x80, 0x80, 0x80);
   }
 
   @Test
   public void testIllegalCodepoints() {
     // Single surrogate
-    assertInvalid(0xed, 0xa0, 0x80);
-    assertInvalid(0xed, 0xad, 0xbf);
-    assertInvalid(0xed, 0xae, 0x80);
-    assertInvalid(0xed, 0xaf, 0xbf);
-    assertInvalid(0xed, 0xb0, 0x80);
-    assertInvalid(0xed, 0xbe, 0x80);
-    assertInvalid(0xed, 0xbf, 0xbf);
+    checkInvalidInts(0xed, 0xa0, 0x80);
+    checkInvalidInts(0xed, 0xad, 0xbf);
+    checkInvalidInts(0xed, 0xae, 0x80);
+    checkInvalidInts(0xed, 0xaf, 0xbf);
+    checkInvalidInts(0xed, 0xb0, 0x80);
+    checkInvalidInts(0xed, 0xbe, 0x80);
+    checkInvalidInts(0xed, 0xbf, 0xbf);
 
     // Paired surrogates
-    assertInvalid(0xed, 0xa0, 0x80, 0xed, 0xb0, 0x80);
-    assertInvalid(0xed, 0xa0, 0x80, 0xed, 0xbf, 0xbf);
-    assertInvalid(0xed, 0xad, 0xbf, 0xed, 0xb0, 0x80);
-    assertInvalid(0xed, 0xad, 0xbf, 0xed, 0xbf, 0xbf);
-    assertInvalid(0xed, 0xae, 0x80, 0xed, 0xb0, 0x80);
-    assertInvalid(0xed, 0xae, 0x80, 0xed, 0xbf, 0xbf);
-    assertInvalid(0xed, 0xaf, 0xbf, 0xed, 0xb0, 0x80);
-    assertInvalid(0xed, 0xaf, 0xbf, 0xed, 0xbf, 0xbf);
+    checkInvalidInts(0xed, 0xa0, 0x80, 0xed, 0xb0, 0x80);
+    checkInvalidInts(0xed, 0xa0, 0x80, 0xed, 0xbf, 0xbf);
+    checkInvalidInts(0xed, 0xad, 0xbf, 0xed, 0xb0, 0x80);
+    checkInvalidInts(0xed, 0xad, 0xbf, 0xed, 0xbf, 0xbf);
+    checkInvalidInts(0xed, 0xae, 0x80, 0xed, 0xb0, 0x80);
+    checkInvalidInts(0xed, 0xae, 0x80, 0xed, 0xbf, 0xbf);
+    checkInvalidInts(0xed, 0xaf, 0xbf, 0xed, 0xb0, 0x80);
+    checkInvalidInts(0xed, 0xaf, 0xbf, 0xed, 0xbf, 0xbf);
   }
 
   @Test
@@ -371,21 +372,21 @@
   @Test
   public void testInvalidBufferSlice() { //these are pure Memory bounds violations
     byte[] bytes  = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
-    assertInvalidSlice(bytes, bytes.length - 3, 4);
-    assertInvalidSlice(bytes, bytes.length, 1);
-    assertInvalidSlice(bytes, bytes.length + 1, 0);
-    assertInvalidSlice(bytes, 0, bytes.length + 1);
+    checkInvalidSlice(bytes, bytes.length - 3, 4);
+    checkInvalidSlice(bytes, bytes.length, 1);
+    checkInvalidSlice(bytes, bytes.length + 1, 0);
+    checkInvalidSlice(bytes, 0, bytes.length + 1);
   }
 
-  private static void assertInvalid(int... bytesAsInt) { //invalid byte sequences
+  private static void checkInvalidInts(int... bytesAsInt) { //invalid byte sequences
     byte[] bytes = new byte[bytesAsInt.length];
     for (int i = 0; i < bytesAsInt.length; i++) {
       bytes[i] = (byte) bytesAsInt[i];
     }
-    assertInvalid(bytes);
+    checkInvalidBytes(bytes);
   }
 
-  private static void assertInvalid(byte[] bytes) {
+  private static void checkInvalidBytes(byte[] bytes) {
     int bytesLen = bytes.length;
     try {
       Memory.wrap(bytes).getCharsFromUtf8(0, bytesLen, new StringBuilder());
@@ -402,12 +403,12 @@
     }
   }
 
-  private static void assertInvalidSlice(byte[] bytes, int index, int size) {
+  private static void checkInvalidSlice(byte[] bytes, int index, int size) {
     try {
       Memory mem = Memory.wrap(bytes);
       mem.getCharsFromUtf8(index, size, new StringBuilder());
       fail();
-    } catch (IllegalArgumentException e) { //Pure bounds violation
+    } catch (MemoryBoundsException e) { //Pure bounds violation
       // Expected.
     }
   }
@@ -415,7 +416,7 @@
   /**
    * Performs round-trip test using the given reference string
    * @param refStr the reference string
-   * @throws IOException
+   * @throws IOException when IOException occurs
    */
   private static void assertRoundTrips(String refStr) throws IOException {
     assertRoundTrips(refStr, refStr.toCharArray().length, 0, -1);
@@ -427,7 +428,7 @@
    * @param refSubCharLen the number of characters expected to be decoded
    * @param offsetBytes starting utf8 byte offset
    * @param utf8LengthBytes length of utf8 bytes
-   * @throws IOException
+   * @throws IOException when IOException occurs
    */
   private static void assertRoundTrips(String refStr, int refSubCharLen, int offsetBytes,
       int utf8LengthBytes) throws IOException {
@@ -504,7 +505,7 @@
 
   @Test
   public void printlnTest() {
-   println("PRINTING: "+this.getClass().getName());
+   println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UtilTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UtilTest.java
index 8dc1081..14a8629 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UtilTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UtilTest.java
@@ -42,6 +42,7 @@
 import java.nio.file.attribute.PosixFileAttributes;
 import java.nio.file.attribute.PosixFilePermissions;
 
+import org.apache.datasketches.memory.MemoryBoundsException;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
@@ -56,16 +57,16 @@
     for (int i = 0; i < k; i++) { wMem.putLong(i << 3, i); }
     long idx = Util.binarySearchLongs(wMem, 0, k - 1, k / 2);
     long val = wMem.getLong(idx << 3);
-    assertEquals(idx, k/2);
-    assertEquals(val, k/2);
+    assertEquals(idx, k / 2);
+    assertEquals(val, k / 2);
 
     idx = Util.binarySearchLongs(wMem, 0, k - 1, k);
     assertEquals(idx, -1024);
   }
 
-  @Test(expectedExceptions = IllegalArgumentException.class)
+  @Test(expectedExceptions = MemoryBoundsException.class)
   public void checkBoundsTest() {
-    UnsafeUtil.checkBounds(999, 2, 1000);
+    ResourceImpl.checkBounds(999, 2, 1000);
   }
 
   @Test
@@ -184,7 +185,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   static void println(final Object o) {
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/VirtualMachineMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/VirtualMachineMemoryTest.java
index 27b6f55..2793b30 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/VirtualMachineMemoryTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/VirtualMachineMemoryTest.java
@@ -19,21 +19,15 @@
 
 package org.apache.datasketches.memory.internal;
 
-import org.apache.datasketches.memory.internal.VirtualMachineMemory;
 import org.testng.annotations.Test;
 
 @SuppressWarnings({"unused"})
 public class VirtualMachineMemoryTest {
 
     @Test
-    public void maxDirectBufferMemory() {
-       assert(VirtualMachineMemory.getMaxDBBMemory() >= 0);
-    }
-
-    @Test
     public void inertPageAlignment() {
       boolean result = VirtualMachineMemory.getIsPageAligned();
       //System.out.println("VM page alignment:" + result);
-      assert(true); //no exception was thrown
+      assert (true); //no exception was thrown
     }
 }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/WritableDirectCopyTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/WritableDirectCopyTest.java
index f52aa34..37519a4 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/WritableDirectCopyTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/WritableDirectCopyTest.java
@@ -22,8 +22,8 @@
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.fail;
 
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryBoundsException;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
 
@@ -35,11 +35,10 @@
 //Copy Within tests
 
   @Test
-  public void checkCopyWithinNativeSmall() throws Exception {
+  public void checkCopyWithinNativeSmall() {
     int memCapacity = 64;
     int half = memCapacity / 2;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.clear();
 
       for (int i = 0; i < half; i++) { //fill first half
@@ -55,13 +54,12 @@
   }
 
   @Test
-  public void checkCopyWithinNativeLarge() throws Exception {
+  public void checkCopyWithinNativeLarge() {
     int memCapacity = (2 << 20) + 64;
     int memCapLongs = memCapacity / 8;
     int halfBytes = memCapacity / 2;
     int halfLongs = memCapLongs / 2;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.clear();
 
       for (int i = 0; i < halfLongs; i++) {
@@ -77,10 +75,9 @@
   }
 
   @Test
-  public void checkCopyWithinNativeOverlap() throws Exception {
+  public void checkCopyWithinNativeOverlap() {
     int memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.clear();
       //println(mem.toHexString("Clear 64", 0, memCapacity));
 
@@ -93,37 +90,33 @@
   }
 
   @Test
-  public void checkCopyWithinNativeSrcBound() throws Exception {
+  public void checkCopyWithinNativeSrcBound() {
     int memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.copyTo(32, mem, 32, 33);  //hit source bound check
       fail("Did Not Catch Assertion Error: source bound");
-    } catch (IllegalArgumentException e) {
+    } catch (MemoryBoundsException e) {
       //pass
     }
   }
 
   @Test
-  public void checkCopyWithinNativeDstBound() throws Exception {
+  public void checkCopyWithinNativeDstBound() {
     int memCapacity = 64;
-    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem = wrh.getWritable();
+    try (WritableMemory mem = WritableMemory.allocateDirect(memCapacity)) {
       mem.copyTo(0, mem, 32, 33);  //hit dst bound check
       fail("Did Not Catch Assertion Error: dst bound");
-    } catch (IllegalArgumentException e) {
+    } catch (MemoryBoundsException e) {
       //pass
     }
   }
 
   @Test
-  public void checkCopyCrossNativeSmall() throws Exception {
+  public void checkCopyCrossNativeSmall() {
     int memCapacity = 64;
 
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity);
-         WritableHandle wrh2 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem1 = wrh1.getWritable();
-      WritableMemory mem2 = wrh2.getWritable();
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity);
+        WritableMemory mem2 = WritableMemory.allocateDirect(memCapacity)) {
 
       for (int i = 0; i < memCapacity; i++) {
         mem1.putByte(i, (byte) i);
@@ -134,21 +127,16 @@
       for (int i = 0; i < memCapacity; i++) {
         assertEquals(mem2.getByte(i), (byte) i);
       }
-      wrh1.close();
-      wrh2.close();
     }
   }
 
   @Test
-  public void checkCopyCrossNativeLarge() throws Exception {
+  public void checkCopyCrossNativeLarge() {
     int memCapacity = (2 << 20) + 64;
     int memCapLongs = memCapacity / 8;
 
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity);
-         WritableHandle wrh2 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem1 = wrh1.getWritable();
-      WritableMemory mem2 = wrh2.getWritable();
-
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity);
+         WritableMemory mem2 = WritableMemory.allocateDirect(memCapacity)) {
       for (int i = 0; i < memCapLongs; i++) {
         mem1.putLong(i * 8, i);
       }
@@ -163,11 +151,9 @@
   }
 
   @Test
-  public void checkCopyCrossNativeAndByteArray() throws Exception {
+  public void checkCopyCrossNativeAndByteArray() {
     int memCapacity = 64;
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem1 = wrh1.getWritable();
-
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity)) {
       for (int i = 0; i < mem1.getCapacity(); i++) {
         mem1.putByte(i, (byte) i);
       }
@@ -183,12 +169,9 @@
   }
 
   @Test
-  public void checkCopyCrossRegionsSameNative() throws Exception {
+  public void checkCopyCrossRegionsSameNative() {
     int memCapacity = 128;
-
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem1 = wrh1.getWritable();
-
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity)) {
       for (int i = 0; i < mem1.getCapacity(); i++) {
         mem1.putByte(i, (byte) i);
       }
@@ -210,11 +193,9 @@
   }
 
   @Test
-  public void checkCopyCrossNativeArrayAndHierarchicalRegions() throws Exception {
+  public void checkCopyCrossNativeArrayAndHierarchicalRegions() {
     int memCapacity = 64;
-    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
-      WritableMemory mem1 = wrh1.getWritable();
-
+    try (WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity)) {
       for (int i = 0; i < mem1.getCapacity(); i++) { //fill with numbers
         mem1.putByte(i, (byte) i);
       }
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/WritableMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/WritableMemoryTest.java
index 1226cc5..91f1089 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/WritableMemoryTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/WritableMemoryTest.java
@@ -38,9 +38,9 @@
   public void wrapBigEndian() {
     ByteBuffer bb = ByteBuffer.allocate(64); //big endian
     WritableMemory wmem = WritableMemory.writableWrap(bb);
-    assertEquals(wmem.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(wmem.getByteOrder(), ByteOrder.BIG_ENDIAN);
     wmem = WritableMemory.writableWrap(bb, ByteOrder.nativeOrder());
-    assertEquals(wmem.getTypeByteOrder(), ByteOrder.LITTLE_ENDIAN);
+    assertEquals(wmem.getByteOrder(), ByteOrder.LITTLE_ENDIAN);
   }
 
   @Test
@@ -54,20 +54,20 @@
   @Test
   public void allocateWithByteOrder() {
     WritableMemory wmem = WritableMemory.allocate(64, ByteOrder.BIG_ENDIAN);
-    assertEquals(wmem.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(wmem.getByteOrder(), ByteOrder.BIG_ENDIAN);
     wmem = WritableMemory.allocate(64, ByteOrder.LITTLE_ENDIAN);
-    assertEquals(wmem.getTypeByteOrder(), ByteOrder.LITTLE_ENDIAN);
+    assertEquals(wmem.getByteOrder(), ByteOrder.LITTLE_ENDIAN);
     wmem = WritableMemory.writableWrap(new byte[64], 32, 32, ByteOrder.BIG_ENDIAN);
-    assertEquals(wmem.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(wmem.getByteOrder(), ByteOrder.BIG_ENDIAN);
   }
 
   @Test
   public void checkGetArray() {
     byte[] byteArr = new byte[64];
     WritableMemory wmem = WritableMemory.writableWrap(byteArr);
-    assertTrue(wmem.getArray() == byteArr);
+    assertTrue(((BaseWritableMemoryImpl) wmem).getArray() == byteArr);
     WritableBuffer wbuf = wmem.asWritableBuffer();
-    assertTrue(wbuf.getArray() == byteArr);
+    assertTrue(((BaseWritableBufferImpl)wbuf).getArray() == byteArr);
   }
 
   @Test(expectedExceptions = IllegalArgumentException.class)
@@ -83,21 +83,21 @@
     WritableMemory wmem1 = WritableMemory.allocate(len);
     //@SuppressWarnings({"EqualsWithItself", "SelfEquals"}) //unsupported
     //SelfEquals for Plexus, EqualsWithItself for IntelliJ
-    //boolean eq1 = wmem1.equals(wmem1); //strict profile complains
+    //boolean eq1 = wmem1.equalTo(wmem1); //strict profile complains
     //assertTrue(eq1);
 
     WritableMemory wmem2 = WritableMemory.allocate(len + 1);
-    assertFalse(wmem1.equals(wmem2));
+    assertFalse(wmem1.equalTo(wmem2));
 
     WritableMemory reg1 = wmem1.writableRegion(0, wmem1.getCapacity());
-    assertTrue(wmem1.equals(reg1));
+    assertTrue(wmem1.equalTo(reg1));
 
     wmem2 = WritableMemory.allocate(len);
     for (int i = 0; i < len; i++) {
       wmem1.putByte(i, (byte) i);
       wmem2.putByte(i, (byte) i);
     }
-    assertTrue(wmem1.equals(wmem2));
+    assertTrue(wmem1.equalTo(wmem2));
     assertTrue(wmem1.equalTo(0, wmem1, 0, len));
 
     reg1 = wmem1.writableRegion(0, wmem1.getCapacity());
@@ -123,14 +123,14 @@
   public void checkEquals2() {
     int len = 23;
     WritableMemory wmem1 = WritableMemory.allocate(len);
-    assertFalse(wmem1.equals(null));
+    assertFalse(wmem1.equalTo(null));
     //@SuppressWarnings({"EqualsWithItself", "SelfEquals"}) //unsupported
     //SelfEquals for Plexus, EqualsWithItself for IntelliJ
-    //boolean eq1 = wmem1.equals(wmem1); //strict profile complains
+    //boolean eq1 = wmem1.equalTo(wmem1); //strict profile complains
     //assertTrue(eq1);
 
     WritableMemory wmem2 = WritableMemory.allocate(len + 1);
-    assertFalse(wmem1.equals(wmem2));
+    assertFalse(wmem1.equalTo(wmem2));
 
     for (int i = 0; i < len; i++) {
       wmem1.putByte(i, (byte) i);
@@ -150,24 +150,24 @@
     byte[] bytes2 = bytes1.clone();
     Memory mem1 = Memory.wrap(bytes1);
     Memory mem2 = Memory.wrap(bytes2);
-    assertTrue(mem1.equals(mem2));
+    assertTrue(mem1.equalTo(mem2));
 
     bytes2[thresh + 10] = (byte) (bytes1[thresh + 10] + 1);
-    assertFalse(mem1.equals(mem2));
+    assertFalse(mem1.equalTo(mem2));
 
     bytes2[thresh + 10] = bytes1[thresh + 10];
     bytes2[(thresh * 2) + 3] = (byte) (bytes1[(thresh * 2) + 3] + 1);
-    assertFalse(mem1.equals(mem2));
+    assertFalse(mem1.equalTo(mem2));
   }
 
   @Test
   public void checkWrapWithBO() {
     WritableMemory wmem = WritableMemory.writableWrap(new byte[0], ByteOrder.BIG_ENDIAN);
-    boolean nativeBO = wmem.getTypeByteOrder() == ByteOrder.nativeOrder();
+    boolean nativeBO = wmem.getByteOrder() == ByteOrder.nativeOrder();
     assertFalse(nativeBO);
     println("" + nativeBO);
     wmem = WritableMemory.writableWrap(new byte[8], ByteOrder.BIG_ENDIAN);
-    nativeBO = wmem.getTypeByteOrder() == ByteOrder.nativeOrder();
+    nativeBO = wmem.getByteOrder() == ByteOrder.nativeOrder();
     assertFalse(nativeBO);
     println("" + nativeBO);
   }
@@ -185,7 +185,7 @@
 
   @Test
   public void printlnTest() {
-    println("PRINTING: "+this.getClass().getName());
+    println("PRINTING: " + this.getClass().getName());
   }
 
   /**
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/XxHash64Test.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/XxHash64Test.java
index 9656420..9c51eb6 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/XxHash64Test.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/XxHash64Test.java
@@ -19,14 +19,23 @@
 
 package org.apache.datasketches.memory.internal;
 
-import static org.apache.datasketches.memory.XxHash.*;
+import static org.apache.datasketches.memory.XxHash.hashBooleanArr;
+import static org.apache.datasketches.memory.XxHash.hashByteArr;
+import static org.apache.datasketches.memory.XxHash.hashCharArr;
+import static org.apache.datasketches.memory.XxHash.hashDoubleArr;
+import static org.apache.datasketches.memory.XxHash.hashFloatArr;
+import static org.apache.datasketches.memory.XxHash.hashIntArr;
+import static org.apache.datasketches.memory.XxHash.hashLong;
+import static org.apache.datasketches.memory.XxHash.hashLongArr;
+import static org.apache.datasketches.memory.XxHash.hashShortArr;
+import static org.apache.datasketches.memory.XxHash.hashString;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
 import java.util.Random;
 import java.util.concurrent.ThreadLocalRandom;
 
-import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Resource;
 import org.apache.datasketches.memory.Memory;
 import org.apache.datasketches.memory.WritableMemory;
 import org.testng.annotations.Test;
@@ -68,7 +77,7 @@
       WritableMemory wmem = WritableMemory.writableWrap(in);
       for (int i = 0; i < j; i++) { wmem.putByte(i, (byte) (-128 + i)); }
 
-      long hash =wmem.xxHash64(offset, bytes, seed);
+      long hash = wmem.xxHash64(offset, bytes, seed);
       assertTrue(hash != 0);
     }
   }
@@ -101,7 +110,7 @@
   }
 
   /**
-   * This simple test compares the output of {@link BaseState#xxHash64(long, long, long)} with the
+   * This simple test compares the output of {@link Resource#xxHash64(long, long, long)} with the
    * output of {@link net.openhft.hashing.LongHashFunction}, that itself is tested against the
    * reference implementation in C.  This increase confidence that the xxHash function implemented
    * in this package is in fact the same xxHash function implemented in C.
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ZeroCapacityTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ZeroCapacityTest.java
index 5979e37..fa500db 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ZeroCapacityTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ZeroCapacityTest.java
@@ -24,12 +24,12 @@
 import java.nio.ByteBuffer;
 
 import org.apache.datasketches.memory.Memory;
-import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.WritableMemory;
-import org.testng.Assert;
 import org.testng.annotations.Test;
 
 /**
+ * Although allocating zero bytes may be a bug, it is tolerated in Java.
+ *
  * @author Lee Rhodes
  */
 public class ZeroCapacityTest {
@@ -43,14 +43,8 @@
     Memory.wrap(ByteBuffer.allocate(0));
     Memory mem3 = Memory.wrap(ByteBuffer.allocateDirect(0));
     mem3.region(0, 0);
-    WritableHandle wh = null;
-    try {
-      wh = WritableMemory.allocateDirect(0);
-      Assert.fail();
-    } catch (IllegalArgumentException ignore) {
-      if (wh != null) { wh.close(); }
-      // expected
-    }
+    WritableMemory mem = WritableMemory.allocateDirect(0);
+    mem.close();
   }
 
   @Test
diff --git a/pom.xml b/pom.xml
index 7085c35..4e57ac2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -99,7 +99,7 @@
     <!-- END:UNIQUE FOR THIS JAVA COMPONENT -->
 
     <!-- Test -->
-    <testng.version>7.5</testng.version>
+    <testng.version>7.5.1</testng.version>
 
     <!-- System-wide properties -->
     <maven.version>3.5.0</maven.version>
diff --git a/tools/MemoryCheckstyle.xml b/tools/MemoryCheckstyle.xml
index fd631a7..95c0988 100644
--- a/tools/MemoryCheckstyle.xml
+++ b/tools/MemoryCheckstyle.xml
@@ -37,8 +37,14 @@
   <property name="severity" value="warning"/>
   <property name="fileExtensions" value="java"/>
 
+  <module name="SuppressionFilter">
+    <property name="file" value="${samedir}/suppressions.xml"/>
+    <property name="optional" value="false"/>
+  </module>
+
+  <!-- Exclude module-info.java files -->
   <module name="BeforeExecutionExclusionFileFilter">
-    <property name="fileNamePattern" value="src[\\/]test[\\/]java[\\/].+$|module\-info\.java.+$"/>
+    <property name="fileNamePattern" value="module\-info\.java$"/>
   </module>
 
   <module name="FileTabCharacter">
@@ -235,6 +241,7 @@
       <property name="severity" value="warning"/>
       <property name="allowEscapesForControlCharacters" value="true"/>
       <property name="allowByTailComment" value="true"/>
+      <property name="allowIfAllCharactersEscaped" value="true"/>
       <property name="allowNonPrintableEscapes" value="true"/>
       <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
     </module>
diff --git a/tools/suppressions.xml b/tools/suppressions.xml
new file mode 100644
index 0000000..58cdce7
--- /dev/null
+++ b/tools/suppressions.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE suppressions PUBLIC
+  "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
+  "https://checkstyle.org/dtds/suppressions_1_2.dtd">
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<suppressions>
+  <!-- Tone down the checking for test code -->
+  <suppress checks="FinalLocalVariable" files=".*[\\/]src[\\/](test|it)[\\/]"/>
+  <suppress checks="AvoidEscapedUnicodeCharacters" files=".*[\\/]src[\\/](test|it)[\\/]"/>
+  <suppress checks="JavadocPackage" files=".*[\\/]src[\\/](test|it)[\\/]"/>
+</suppressions>