diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go
index f51e6363f66a18bbfc2b9d408ec40b9578aec98e..1643da967973672c454e85b93b823e2ea11f4ef7 100644
--- a/core/vm/instructions_test.go
+++ b/core/vm/instructions_test.go
@@ -36,6 +36,7 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
 		stack = newstack()
 		pc    = uint64(0)
 	)
+	env.interpreter.intPool = poolOfIntPools.get()
 	for i, test := range tests {
 		x := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
 		shift := new(big.Int).SetBytes(common.Hex2Bytes(test.y))
@@ -64,6 +65,7 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
 			}
 		}
 	}
+	poolOfIntPools.put(env.interpreter.intPool)
 }
 
 func TestByteOp(t *testing.T) {
@@ -71,6 +73,7 @@ func TestByteOp(t *testing.T) {
 		env   = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
 		stack = newstack()
 	)
+	env.interpreter.intPool = poolOfIntPools.get()
 	tests := []struct {
 		v        string
 		th       uint64
@@ -97,6 +100,7 @@ func TestByteOp(t *testing.T) {
 			t.Fatalf("Expected  [%v] %v:th byte to be %v, was %v.", test.v, test.th, test.expected, actual)
 		}
 	}
+	poolOfIntPools.put(env.interpreter.intPool)
 }
 
 func TestSHL(t *testing.T) {
@@ -432,6 +436,7 @@ func TestOpMstore(t *testing.T) {
 		stack = newstack()
 		mem   = NewMemory()
 	)
+	env.interpreter.intPool = poolOfIntPools.get()
 	mem.Resize(64)
 	pc := uint64(0)
 	v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
@@ -445,6 +450,7 @@ func TestOpMstore(t *testing.T) {
 	if common.Bytes2Hex(mem.Get(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
 		t.Fatalf("Mstore failed to overwrite previous value")
 	}
+	poolOfIntPools.put(env.interpreter.intPool)
 }
 
 func BenchmarkOpMstore(bench *testing.B) {
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index 7090e0261fc0c67b64ddf32b951e0a22c23ef134..0d6038cbbf70d513515ac2c9d0bc2f1547ca1489 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -77,7 +77,6 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
 		evm:      evm,
 		cfg:      cfg,
 		gasTable: evm.ChainConfig().GasTable(evm.BlockNumber),
-		intPool:  newIntPool(),
 	}
 }
 
@@ -104,6 +103,14 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack
 // considered a revert-and-consume-all-gas operation except for
 // errExecutionReverted which means revert-and-keep-gas-left.
 func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) {
+	if in.intPool == nil {
+		in.intPool = poolOfIntPools.get()
+		defer func() {
+			poolOfIntPools.put(in.intPool)
+			in.intPool = nil
+		}()
+	}
+
 	// Increment the call depth which is restricted to 1024
 	in.evm.depth++
 	defer func() { in.evm.depth-- }()
@@ -133,6 +140,9 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er
 	)
 	contract.Input = input
 
+	// Reclaim the stack as an int pool when the execution stops
+	defer func() { in.intPool.put(stack.data...) }()
+
 	if in.cfg.Debug {
 		defer func() {
 			if err != nil {
diff --git a/core/vm/intpool.go b/core/vm/intpool.go
index 5dbda18eeefa0b1e624a837f8085f08880a35272..917a78d560ff5c6d1126976b2f3c2b8d063c5042 100644
--- a/core/vm/intpool.go
+++ b/core/vm/intpool.go
@@ -16,7 +16,10 @@
 
 package vm
 
-import "math/big"
+import (
+	"math/big"
+	"sync"
+)
 
 var checkVal = big.NewInt(-42)
 
@@ -65,3 +68,39 @@ func (p *intPool) put(is ...*big.Int) {
 		p.pool.push(i)
 	}
 }
+
+// The intPool pool's default capacity
+const poolDefaultCap = 25
+
+// intPoolPool manages a pool of intPools.
+type intPoolPool struct {
+	pools []*intPool
+	lock  sync.Mutex
+}
+
+var poolOfIntPools = &intPoolPool{
+	pools: make([]*intPool, 0, poolDefaultCap),
+}
+
+// get is looking for an available pool to return.
+func (ipp *intPoolPool) get() *intPool {
+	ipp.lock.Lock()
+	defer ipp.lock.Unlock()
+
+	if len(poolOfIntPools.pools) > 0 {
+		ip := ipp.pools[len(ipp.pools)-1]
+		ipp.pools = ipp.pools[:len(ipp.pools)-1]
+		return ip
+	}
+	return newIntPool()
+}
+
+// put a pool that has been allocated with get.
+func (ipp *intPoolPool) put(ip *intPool) {
+	ipp.lock.Lock()
+	defer ipp.lock.Unlock()
+
+	if len(ipp.pools) < cap(ipp.pools) {
+		ipp.pools = append(ipp.pools, ip)
+	}
+}
diff --git a/core/vm/intpool_test.go b/core/vm/intpool_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6c0d00f3ce5c7161abc6d6a57f799f3e1eb99fff
--- /dev/null
+++ b/core/vm/intpool_test.go
@@ -0,0 +1,55 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package vm
+
+import (
+	"testing"
+)
+
+func TestIntPoolPoolGet(t *testing.T) {
+	poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap)
+
+	nip := poolOfIntPools.get()
+	if nip == nil {
+		t.Fatalf("Invalid pool allocation")
+	}
+}
+
+func TestIntPoolPoolPut(t *testing.T) {
+	poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap)
+
+	nip := poolOfIntPools.get()
+	if len(poolOfIntPools.pools) != 0 {
+		t.Fatalf("Pool got added to list when none should have been")
+	}
+
+	poolOfIntPools.put(nip)
+	if len(poolOfIntPools.pools) == 0 {
+		t.Fatalf("Pool did not get added to list when one should have been")
+	}
+}
+
+func TestIntPoolPoolReUse(t *testing.T) {
+	poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap)
+	nip := poolOfIntPools.get()
+	poolOfIntPools.put(nip)
+	poolOfIntPools.get()
+
+	if len(poolOfIntPools.pools) != 0 {
+		t.Fatalf("Invalid number of pools. Got %d, expected %d", len(poolOfIntPools.pools), 0)
+	}
+}