diff --git a/src/memory/bump.rs b/src/memory/bump.rs
index 16c837783595c343eb389be8c843c85ec6b4ec4f..6453b108a511122ce9206ba791cce00d98b2c2bb 100644
--- a/src/memory/bump.rs
+++ b/src/memory/bump.rs
@@ -1,4 +1,4 @@
-//! # Area frame allocator
+//! # Bump frame allocator
 //! Some code was borrowed from [Phil Opp's Blog](http://os.phil-opp.com/allocating-frames.html)
 
 use paging::PhysicalAddress;
@@ -15,8 +15,8 @@ pub struct BumpAllocator {
 }
 
 impl BumpAllocator {
-    pub fn new(kernel_start: usize, kernel_end: usize, memory_areas: MemoryAreaIter) -> BumpAllocator {
-        let mut allocator = BumpAllocator {
+    pub fn new(kernel_start: usize, kernel_end: usize, memory_areas: MemoryAreaIter) -> Self {
+        let mut allocator = Self {
             next_free_frame: Frame::containing_address(PhysicalAddress::new(0)),
             current_area: None,
             areas: memory_areas,
@@ -43,6 +43,8 @@ impl BumpAllocator {
 }
 
 impl FrameAllocator for BumpAllocator {
+    fn set_noncore(&mut self, noncore: bool) {}
+    
     fn free_frames(&self) -> usize {
         let mut count = 0;
 
diff --git a/src/memory/mod.rs b/src/memory/mod.rs
index 01216b18906e639064da236b74ea7d48917b297e..fb4275bdb45401622dd3d85c48a62e0aac0c272a 100644
--- a/src/memory/mod.rs
+++ b/src/memory/mod.rs
@@ -4,10 +4,12 @@
 pub use paging::{PAGE_SIZE, PhysicalAddress};
 
 use self::bump::BumpAllocator;
+use self::recycle::RecycleAllocator;
 
 use spin::Mutex;
 
 pub mod bump;
+pub mod recycle;
 
 /// The current memory map. It's size is maxed out to 512 entries, due to it being
 /// from 0x500 to 0x5000 (800 is the absolute total)
@@ -64,7 +66,7 @@ impl Iterator for MemoryAreaIter {
     }
 }
 
-static ALLOCATOR: Mutex<Option<BumpAllocator>> = Mutex::new(None);
+static ALLOCATOR: Mutex<Option<RecycleAllocator<BumpAllocator>>> = Mutex::new(None);
 
 /// Init memory module
 /// Must be called once, and only once,
@@ -77,7 +79,17 @@ pub unsafe fn init(kernel_start: usize, kernel_end: usize) {
         }
     }
 
-    *ALLOCATOR.lock() = Some(BumpAllocator::new(kernel_start, kernel_end, MemoryAreaIter::new(MEMORY_AREA_FREE)));
+    *ALLOCATOR.lock() = Some(RecycleAllocator::new(BumpAllocator::new(kernel_start, kernel_end, MemoryAreaIter::new(MEMORY_AREA_FREE))));
+}
+
+/// Init memory module after core
+/// Must be called once, and only once,
+pub unsafe fn init_noncore() {
+    if let Some(ref mut allocator) = *ALLOCATOR.lock() {
+        allocator.set_noncore(true)
+    } else {
+        panic!("frame allocator not initialized");
+    }
 }
 
 /// Get the number of frames available
@@ -172,6 +184,7 @@ impl Iterator for FrameIter {
 }
 
 pub trait FrameAllocator {
+    fn set_noncore(&mut self, noncore: bool);
     fn free_frames(&self) -> usize;
     fn used_frames(&self) -> usize;
     fn allocate_frames(&mut self, size: usize) -> Option<Frame>;
diff --git a/src/memory/recycle.rs b/src/memory/recycle.rs
new file mode 100644
index 0000000000000000000000000000000000000000..34af97e208ef5008cbab50d22aa08ea5dffbb8a4
--- /dev/null
+++ b/src/memory/recycle.rs
@@ -0,0 +1,126 @@
+//! Recycle allocator
+//! Uses freed frames if possible, then uses inner allocator
+
+use collections::Vec;
+
+use paging::PhysicalAddress;
+
+use super::{Frame, FrameAllocator, MemoryArea, MemoryAreaIter};
+
+pub struct RecycleAllocator<T: FrameAllocator> {
+    inner: T,
+    noncore: bool,
+    free: Vec<(usize, usize)>,
+}
+
+impl<T: FrameAllocator> RecycleAllocator<T> {
+    pub fn new(inner: T) -> Self {
+        Self {
+            inner: inner,
+            noncore: false,
+            free: Vec::new(),
+        }
+    }
+
+    fn free_count(&self) -> usize {
+        let mut count = 0;
+        for free in self.free.iter() {
+            count += free.1;
+        }
+        println!("Free count: {} in {} entries", count, self.free.len());
+        count
+    }
+
+    fn merge(&mut self, address: usize, count: usize) -> bool {
+        for i in 0 .. self.free.len() {
+            let changed = {
+                let mut free = &mut self.free[i];
+                if address + count * 4096 == free.0 {
+                    free.0 = address;
+                    free.1 += count;
+                    true
+                } else if free.0 + free.1 * 4096 == address {
+                    free.1 += count;
+                    true
+                } else {
+                    false
+                }
+            };
+
+            if changed {
+                //TODO: Use do not use recursion
+                let (address, count) = self.free[i];
+                if self.merge(address, count) {
+                    self.free.remove(i);
+                }
+                return true;
+            }
+        }
+
+        false
+    }
+}
+
+impl<T: FrameAllocator> FrameAllocator for RecycleAllocator<T> {
+    fn set_noncore(&mut self, noncore: bool) {
+        self.noncore = noncore;
+    }
+
+    fn free_frames(&self) -> usize {
+        self.inner.free_frames() + self.free_count()
+    }
+
+    fn used_frames(&self) -> usize {
+        self.inner.used_frames() - self.free_count()
+    }
+
+    fn allocate_frames(&mut self, count: usize) -> Option<Frame> {
+        if count == 1 {
+            if ! self.free.is_empty() {
+                let mut i = 0;
+                {
+                    let mut small = self.free[i];
+                    for j in 1..self.free.len() {
+                        let free = self.free[j];
+                        // Later entries can be removed faster
+                        if free.1 <= small.1 {
+                            i = j;
+                            small = free;
+                        }
+                    }
+                }
+
+                let (address, remove) = {
+                    let free = &mut self.free[i];
+                    free.1 -= 1;
+                    (free.0 + free.1 * 4096, free.1 == 0)
+                };
+
+                if remove {
+                    self.free.remove(i);
+                }
+                
+                //println!("Restoring frame {:?}, {}", frame, count);
+                Some(Frame::containing_address(PhysicalAddress::new(address)))
+            } else {
+                //println!("No saved frames {}", count);
+                self.inner.allocate_frames(count)
+            }
+        } else {
+            println!("Could not restore frame {}", count);
+            self.inner.allocate_frames(count)
+        }
+    }
+
+    fn deallocate_frames(&mut self, frame: Frame, count: usize) {
+        if self.noncore {
+            let address = frame.start_address().get();
+            if ! self.merge(address, count) {
+                self.free.push((address, count));
+            }
+        } else {
+            println!("Could not save frame {:?}, {}", frame, count);
+            self.inner.deallocate_frames(frame, count);
+        }
+    }
+}
diff --git a/src/start.rs b/src/start.rs
index 4a42dfa8e2b254561e991f2d735bde634cab9590..2bf9f59102cc1f149c66168cf25a479db12b6565 100644
--- a/src/start.rs
+++ b/src/start.rs
@@ -123,6 +123,9 @@ pub unsafe extern fn kstart() -> ! {
         // Initialize all of the non-core devices not otherwise needed to complete initialization
         device::init_noncore();
 
+        // Initialize memory functions after core has loaded
+        memory::init_noncore();
+
         BSP_READY.store(true, Ordering::SeqCst);
     }