diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 6a9ea367107..ed41f30e291 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -43,6 +43,7 @@
  *
  *-------------------------------------------------------------------------
  */
+#include <execinfo.h>
 
 #include "postgres.h"
 
@@ -264,6 +265,114 @@ static AllocSetFreeList context_freelists[2] =
 	}
 };
 
+typedef struct backtrace_cache_entry
+{
+	void   *ptr;
+	char   *symbol;
+} backtrace_cache_entry;
+
+
+#define BACKTRACE_CACHE_MAX_SIZE 8192
+static int backtrace_cache_size = -1;
+static backtrace_cache_entry backtrace_cache[BACKTRACE_CACHE_MAX_SIZE];
+
+static int
+backtrace_cache_cmp(const void *a, const void *b)
+{
+	backtrace_cache_entry *ca = (backtrace_cache_entry *) a;
+	backtrace_cache_entry *cb = (backtrace_cache_entry *) b;
+
+	if (ca->ptr < cb->ptr)
+		return -1;
+	else if (ca->ptr > cb->ptr)
+		return 1;
+	else
+		return 0;
+}
+
+static char *
+backtrace_cache_lookup(void *ptr)
+{
+	char **strings = NULL;
+	char *str = NULL;
+
+	if (backtrace_cache_size < 0)
+	{
+		backtrace_cache_size = 0;
+		memset(backtrace_cache, 0, sizeof(backtrace_cache));
+	}
+
+	if (backtrace_cache_size > 0)
+	{
+		backtrace_cache_entry key;
+		backtrace_cache_entry *res;
+
+		key.ptr = ptr;
+		key.symbol = NULL;
+
+		res = bsearch(&key,
+			   backtrace_cache, backtrace_cache_size, sizeof(backtrace_cache_entry),
+			   backtrace_cache_cmp);
+
+		if (res != NULL)
+			return strdup(res->symbol);
+	}
+
+	strings = backtrace_symbols(&ptr, 1);
+
+	Assert(strings != NULL);
+
+	str = strdup(strings[0]);
+	free(strings);
+
+	if (backtrace_cache_size < BACKTRACE_CACHE_MAX_SIZE)
+	{
+		backtrace_cache[backtrace_cache_size].ptr = ptr;
+		backtrace_cache[backtrace_cache_size].symbol = strdup(str);
+		backtrace_cache_size++;
+
+		qsort(backtrace_cache, backtrace_cache_size, sizeof(backtrace_cache_entry),
+		   backtrace_cache_cmp);
+	}
+
+	return str;
+}
+
+static inline void
+memtrace_log(char *action, MemoryContext context, void *chunk, Size size)
+{
+	char	bt[8192];
+	int	nptrs;
+	void   *buffer[16];
+	char   *ptr = bt;
+
+	/* interested only in Portal Context */
+	if (context != PortalContext)
+		return;
+
+	nptrs = backtrace(buffer, 16);
+
+	memset(bt, 0, sizeof(bt));
+
+	for (int i = 0; i < nptrs; i++)
+	{
+		char *symbol = backtrace_cache_lookup(buffer[i]);
+
+		if (i > 0)
+		{
+			*ptr = '/';
+			ptr++;
+		}
+
+		ptr = stpcpy(ptr, symbol);
+		free(symbol);
+	}
+
+	elog(LOG, "MEMTRACE %s context %p chunk %p size %ld location %s", action, context, chunk, size, bt);
+}
+
+#define MEMTRACE(action, context, chunk, size)		memtrace_log((action), (context), (chunk), (size))
+
 
 /* ----------
  * AllocSetFreeIndex -
@@ -1028,7 +1137,11 @@ AllocSetAlloc(MemoryContext context, Size size, int flags)
 	 * AllocSetAllocLarge().
 	 */
 	if (size > set->allocChunkLimit)
-		return AllocSetAllocLarge(context, size, flags);
+	{
+		void *p = AllocSetAllocLarge(context, size, flags);
+		MEMTRACE("allocate", context, p, size);
+		return p;
+	}
 
 	/*
 	 * Request is small enough to be treated as a chunk.  Look in the
@@ -1076,6 +1189,8 @@ AllocSetAlloc(MemoryContext context, Size size, int flags)
 		/* Disallow access to the chunk header. */
 		VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
 
+		MEMTRACE("allocate", context, MemoryChunkGetPointer(chunk), size);
+
 		return MemoryChunkGetPointer(chunk);
 	}
 
@@ -1093,10 +1208,18 @@ AllocSetAlloc(MemoryContext context, Size size, int flags)
 	 * chunk into that block.  Else must start a new one.
 	 */
 	if (unlikely(availspace < (chunk_size + ALLOC_CHUNKHDRSZ)))
-		return AllocSetAllocFromNewBlock(context, size, flags, fidx);
+	{
+		void *p = AllocSetAllocFromNewBlock(context, size, flags, fidx);
+		MEMTRACE("allocate", context, p, size);
+		return p;
+	}
 
 	/* There's enough space on the current block, so allocate from that */
-	return AllocSetAllocChunkFromBlock(context, block, size, chunk_size, fidx);
+	{
+		void *p = AllocSetAllocChunkFromBlock(context, block, size, chunk_size, fidx);
+		MEMTRACE("allocate", context, p, size);
+		return p;
+	}
 }
 
 /*
@@ -1126,6 +1249,8 @@ AllocSetFree(void *pointer)
 
 		set = block->aset;
 
+		MEMTRACE("free", (MemoryContext) set, pointer, 0);
+
 #ifdef MEMORY_CONTEXT_CHECKING
 		{
 			/* Test for someone scribbling on unused space in chunk */
@@ -1170,6 +1295,8 @@ AllocSetFree(void *pointer)
 		Assert(AllocBlockIsValid(block));
 		set = block->aset;
 
+		MEMTRACE("free", (MemoryContext) set, pointer, 0);
+
 		fidx = MemoryChunkGetValue(chunk);
 		Assert(FreeListIdxIsValid(fidx));
 		link = GetFreeListLink(chunk);
@@ -1268,6 +1395,8 @@ AllocSetRealloc(void *pointer, Size size, int flags)
 
 		set = block->aset;
 
+		MEMTRACE("free", (MemoryContext) set, pointer, 0);
+
 		/* only check size in paths where the limits could be hit */
 		MemoryContextCheckSize((MemoryContext) set, size, flags);
 
@@ -1373,6 +1502,8 @@ AllocSetRealloc(void *pointer, Size size, int flags)
 		/* Disallow access to the chunk header. */
 		VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
 
+		MEMTRACE("allocate", (MemoryContext) set, pointer, size);
+
 		return pointer;
 	}
 
