diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
index afe1fbe86e60e3a01bf8ecf1449578dbb6bce7e1..061fc37d8041dd88e6331abf4430ea91cd99bbc7 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
@@ -32,9 +32,10 @@ import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -1598,8 +1599,11 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
     @TruffleBoundary
     public void R_PreserveObject(Object obj) {
         guaranteeInstanceOf(obj, RObject.class);
-        HashSet<RObject> list = getContext().preserveList;
-        list.add((RObject) obj);
+        IdentityHashMap<RObject, AtomicInteger> preserveList = getContext().preserveList;
+        AtomicInteger prevCnt = preserveList.putIfAbsent((RObject) obj, new AtomicInteger(1));
+        if (prevCnt != null) {
+            prevCnt.incrementAndGet();
+        }
     }
 
     @Override
@@ -1607,9 +1611,17 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
     public void R_ReleaseObject(Object obj) {
         guaranteeInstanceOf(obj, RObject.class);
         RFFIContext context = getContext();
-        HashSet<RObject> list = context.preserveList;
-        if (list.remove(obj)) {
-            context.registerReferenceUsedInNative(obj);
+        IdentityHashMap<RObject, AtomicInteger> preserveList = context.preserveList;
+        AtomicInteger atomicInteger = preserveList.get(obj);
+        if (atomicInteger != null) {
+            int decrementAndGet = atomicInteger.decrementAndGet();
+            if (decrementAndGet == 0) {
+                // remove from "list"
+                preserveList.remove(obj);
+                context.registerReferenceUsedInNative(obj);
+            }
+        } else {
+            // TODO report ?
         }
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java
index d7c4b530deb07b92c8c632c3cfb218ff5de1603a..407d1eae6fca4c187f343ae3998ea3990c2feb4f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java
@@ -23,7 +23,10 @@
 package com.oracle.truffle.r.runtime.ffi;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.interop.TruffleObject;
@@ -74,7 +77,7 @@ public abstract class RFFIContext extends RFFI {
      * FastR equivalent of GNUR's special dedicated global list that is GC root and so any vectors
      * added to it will be guaranteed to be preserved.
      */
-    public final HashSet<RObject> preserveList = new HashSet<>();
+    public final IdentityHashMap<RObject, AtomicInteger> preserveList = new IdentityHashMap<>();
 
     public abstract TruffleObject lookupNativeFunction(NativeFunction function);