diff --git a/ebpfcat/arraymap.py b/ebpfcat/arraymap.py
index c687d46d8ae0fde3945df563ad275448a637be65..6f836f22541983b2cea349e8396c1dbd947f8794 100644
--- a/ebpfcat/arraymap.py
+++ b/ebpfcat/arraymap.py
@@ -16,19 +16,19 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 from itertools import chain
+from mmap import mmap
 from struct import pack_into, unpack_from, calcsize
 
-from .ebpf import FuncId, Map, MemoryDesc
-from .bpf import create_map, lookup_elem, MapType, update_elem
+from .ebpf import FuncId, Map, Memory, MemoryDesc, Opcode, SubProgram
+from .bpf import create_map, lookup_elem, MapType, MapFlags, update_elem
 
 
 class ArrayGlobalVarDesc(MemoryDesc):
     base_register = 0
 
-    def __init__(self, map, fmt, write=False):
+    def __init__(self, map, fmt):
         self.map = map
         self.fmt = fmt
-        self.write = write
 
     def fmt_addr(self, ebpf):
         return self.fmt, ebpf.__dict__[self.name]
@@ -63,49 +63,16 @@ class ArrayGlobalVarDesc(MemoryDesc):
 
 class ArrayMapAccess:
     """This is the array map proper"""
-    def __init__(self, fd, write_size, size):
-        self.fd = fd
-        self.write_size = write_size
+    def __init__(self, data, size):
+        self.data = data
         self.size = size
-        self.data = bytearray(size)
-
-    def read(self):
-        """read all variables in the map from EBPF to user space"""
-        self.data = lookup_elem(self.fd, b"\0\0\0\0", self.size)
-
-    def write(self):
-        """write all variables in the map from user space to EBPF
-
-        *all* variables are written, even those not marked ``write=True``
-        """
-        update_elem(self.fd, b"\0\0\0\0", self.data, 0)
-
-    def readwrite(self):
-        """read variables from EBPF and write them out immediately
-
-        This reads all variables, swaps in the user-modified values for
-        the ``write=True`` variables, and writes the out again
-        immediately.
-
-        This means that even the read-only variables will be overwritten
-        with the values we have just read. If the EBPF program changed
-        the value in the meantime, that may be a problem.
-
-        Note that after this method returns, all *write* variables
-        will have the value from the EBPF program in user space, and
-        vice-versa.
-        """
-        write = self.data[:self.write_size]
-        data = lookup_elem(self.fd, b"\0\0\0\0", self.size)
-        self.data[:] = data
-        data[:self.write_size] = write
-        update_elem(self.fd, b"\0\0\0\0", data, 0)
 
 
 class ArrayMap(Map):
     """A descriptor for an array map"""
-    def globalVar(self, fmt="I", write=False):
-        return ArrayGlobalVarDesc(self, fmt, write)
+
+    def globalVar(self, fmt="I"):
+        return ArrayGlobalVarDesc(self, fmt)
 
     def collect(self, ebpf):
         collection = []
@@ -113,32 +80,25 @@ class ArrayMap(Map):
         for prog in chain([ebpf], ebpf.subprograms):
             for k, v in prog.__class__.__dict__.items():
                 if isinstance(v, ArrayGlobalVarDesc):
-                    collection.append((v.write, calcsize(v.fmt), prog, k))
-        collection.sort(key=lambda t: t[:2], reverse=True)
+                    collection.append((calcsize(v.fmt), prog, k))
+        collection.sort(key=lambda t: t[0], reverse=True)
         position = 0
-        last_write = write = True
-        for write, size, prog, name in collection:
-            if last_write != write:
-                position = (position + 7) & -8
-                write_size = position
+        for size, prog, name in collection:
             prog.__dict__[name] = position
             position += size
-            last_write = write
-        if write:  # there are read variables
-            return position, position
-        else:
-            return write_size, position
+        return position
 
     def __set_name__(self, owner, name):
         self.name = name
 
     def init(self, ebpf):
         setattr(ebpf, self.name, 0)
-        write_size, size = self.collect(ebpf)
+        size = self.collect(ebpf)
         if not size:  # nobody is actually using the map
             return
-        fd = create_map(MapType.ARRAY, 4, size, 1)
-        setattr(ebpf, self.name, ArrayMapAccess(fd, write_size, size))
+        fd = create_map(MapType.ARRAY, 4, size, 1, MapFlags.MMAPABLE)
+        data = mmap(fd, size)
+        setattr(ebpf, self.name, ArrayMapAccess(data, size))
         with ebpf.save_registers(list(range(6))), ebpf.get_stack(4) as stack:
             ebpf.mI[ebpf.r10 + stack] = 0
             ebpf.r1 = ebpf.get_fd(fd)
diff --git a/ebpfcat/bpf.py b/ebpfcat/bpf.py
index b9985af20f10f491f688f6f0100043d6e650f89f..2da7527b3a88285e3ad96b63dee697d08f60b74d 100644
--- a/ebpfcat/bpf.py
+++ b/ebpfcat/bpf.py
@@ -19,7 +19,7 @@
 A module that wraps the `bpf` system call in Python, using `ctypes`.
 """
 from ctypes import CDLL, c_int, get_errno, cast, c_void_p, create_string_buffer, c_char_p, addressof, c_char
-from enum import Enum
+from enum import Enum, Flag
 from struct import pack, unpack
 from platform import machine
 
@@ -60,6 +60,10 @@ class MapType(Enum):
     SOCKHASH = 18
 
 
+class MapFlags(Flag):
+    MMAPABLE = 1 << 10
+
+
 class ProgType(Enum):
     UNSPEC = 0
     SOCKET_FILTER = 1
@@ -96,9 +100,12 @@ def bpf(cmd, fmt, *args):
         raise OSError(get_errno(), strerror(get_errno()))
     return ret, unpack(fmt, attr.raw)
 
-def create_map(map_type, key_size, value_size, max_entries):
+def create_map(map_type, key_size, value_size, max_entries,
+               attributes=MapFlags(0)):
     assert isinstance(map_type, MapType)
-    return bpf(0, "IIII", map_type.value, key_size, value_size, max_entries)[0]
+    assert isinstance(attributes, MapFlags)
+    return bpf(0, "IIIII", map_type.value, key_size, value_size, max_entries,
+               attributes.value)[0]
 
 def lookup_elem(fd, key, size):
     value = bytearray(size)
diff --git a/ebpfcat/ebpfcat.py b/ebpfcat/ebpfcat.py
index ba228b64aa665cfe3e33698b64e0cd845a87f1ec..a530fff0cf11ee435dfea2130c35a8051d0185e3 100644
--- a/ebpfcat/ebpfcat.py
+++ b/ebpfcat/ebpfcat.py
@@ -175,7 +175,8 @@ class TerminalVar:
 
 class DeviceVar(ArrayGlobalVarDesc):
     def __init__(self, size="I", write=False):
-        super().__init__(FastSyncGroup.properties, size, write)
+        super().__init__(FastSyncGroup.properties, size)
+        self.write = write
 
     def __get__(self, instance, owner):
         if instance is None:
@@ -316,7 +317,6 @@ class FastEtherCat(SimpleEtherCat):
         lastcounts = [0] * 64
         while True:
             t0 = time()
-            self.ebpf.variables.read()
             counts = self.ebpf.counters
             for i, sg in self.sync_groups.items():
                 if ((counts[i] ^ lastcounts[i]) & 0xffff == 0