diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp
index 756b9599fb8..55b41a0b605 100644
--- a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp
+++ b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,8 @@
 #include "runtime/mutexLocker.hpp"
 #include "runtime/thread.inline.hpp"
 
+#include <new>
+
 PtrQueue::PtrQueue(PtrQueueSet* qset, bool permanent, bool active) :
   _qset(qset), _buf(NULL), _index(0), _sz(0), _active(active),
   _permanent(permanent), _lock(NULL)
@@ -87,6 +89,19 @@ void PtrQueue::locking_enqueue_completed_buffer(void** buf) {
 }
 
 
+BufferNode* BufferNode::allocate(size_t byte_size) {
+  assert(byte_size > 0, "precondition");
+  assert(is_size_aligned(byte_size, sizeof(void**)),
+         "Invalid buffer size " SIZE_FORMAT, byte_size);
+  void* data = NEW_C_HEAP_ARRAY(char, buffer_offset() + byte_size, mtGC);
+  return new (data) BufferNode;
+}
+
+void BufferNode::deallocate(BufferNode* node) {
+  node->~BufferNode();
+  FREE_C_HEAP_ARRAY(char, node);
+}
+
 PtrQueueSet::PtrQueueSet(bool notify_when_complete) :
   _max_completed_queue(0),
   _cbl_mon(NULL), _fl_lock(NULL),
@@ -123,17 +138,23 @@ void PtrQueueSet::initialize(Monitor* cbl_mon,
 
 void** PtrQueueSet::allocate_buffer() {
   assert(_sz > 0, "Didn't set a buffer size.");
-  MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
-  if (_fl_owner->_buf_free_list != NULL) {
-    void** res = BufferNode::make_buffer_from_node(_fl_owner->_buf_free_list);
-    _fl_owner->_buf_free_list = _fl_owner->_buf_free_list->next();
-    _fl_owner->_buf_free_list_sz--;
-    return res;
-  } else {
-    // Allocate space for the BufferNode in front of the buffer.
-    char *b =  NEW_C_HEAP_ARRAY(char, _sz + BufferNode::aligned_size(), mtGC);
-    return BufferNode::make_buffer_from_block(b);
+  BufferNode* node = NULL;
+  {
+    MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
+    node = _fl_owner->_buf_free_list;
+    if (node != NULL) {
+      _fl_owner->_buf_free_list = node->next();
+      _fl_owner->_buf_free_list_sz--;
+    }
   }
+  if (node == NULL) {
+    node = BufferNode::allocate(_sz);
+  } else {
+    // Reinitialize buffer obtained from free list.
+    node->set_index(0);
+    node->set_next(NULL);
+  }
+  return BufferNode::make_buffer_from_node(node);
 }
 
 void PtrQueueSet::deallocate_buffer(void** buf) {
@@ -150,13 +171,13 @@ void PtrQueueSet::reduce_free_list() {
   // For now we'll adopt the strategy of deleting half.
   MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag);
   size_t n = _buf_free_list_sz / 2;
-  while (n > 0) {
-    assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong.");
-    void* b = BufferNode::make_block_from_node(_buf_free_list);
-    _buf_free_list = _buf_free_list->next();
-    FREE_C_HEAP_ARRAY(char, b);
-    _buf_free_list_sz --;
-    n--;
+  for (size_t i = 0; i < n; ++i) {
+    assert(_buf_free_list != NULL,
+           "_buf_free_list_sz is wrong: " SIZE_FORMAT, _buf_free_list_sz);
+    BufferNode* node = _buf_free_list;
+    _buf_free_list = node->next();
+    _buf_free_list_sz--;
+    BufferNode::deallocate(node);
   }
 }
 
@@ -236,8 +257,9 @@ bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) {
 
 void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) {
   MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
-  BufferNode* cbn = BufferNode::new_from_buffer(buf);
+  BufferNode* cbn = BufferNode::make_node_from_buffer(buf);
   cbn->set_index(index);
+  cbn->set_next(NULL);
   if (_completed_buffers_tail == NULL) {
     assert(_completed_buffers_head == NULL, "Well-formedness");
     _completed_buffers_head = cbn;
diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp
index 707d591c0c0..a2207641238 100644
--- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp
+++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,6 @@
 // the addresses of modified old-generation objects.  This type supports
 // this operation.
 
-// The definition of placement operator new(size_t, void*) in the <new>.
-#include <new>
-
 class PtrQueueSet;
 class PtrQueue VALUE_OBJ_CLASS_SPEC {
   friend class VMStructs;
@@ -168,42 +165,38 @@ protected:
 class BufferNode {
   size_t _index;
   BufferNode* _next;
-public:
+  void* _buffer[1];             // Pseudo flexible array member.
+
   BufferNode() : _index(0), _next(NULL) { }
+  ~BufferNode() { }
+
+  static size_t buffer_offset() {
+    return offset_of(BufferNode, _buffer);
+  }
+
+public:
   BufferNode* next() const     { return _next;  }
   void set_next(BufferNode* n) { _next = n;     }
   size_t index() const         { return _index; }
   void set_index(size_t i)     { _index = i;    }
 
-  // Align the size of the structure to the size of the pointer
-  static size_t aligned_size() {
-    static const size_t alignment = round_to(sizeof(BufferNode), sizeof(void*));
-    return alignment;
+  // Allocate a new BufferNode with the "buffer" having size bytes.
+  static BufferNode* allocate(size_t byte_size);
+
+  // Free a BufferNode.
+  static void deallocate(BufferNode* node);
+
+  // Return the BufferNode containing the buffer.
+  static BufferNode* make_node_from_buffer(void** buffer) {
+    return reinterpret_cast<BufferNode*>(
+      reinterpret_cast<char*>(buffer) - buffer_offset());
   }
 
-  // BufferNode is allocated before the buffer.
-  // The chunk of memory that holds both of them is a block.
-
-  // Produce a new BufferNode given a buffer.
-  static BufferNode* new_from_buffer(void** buf) {
-    return new (make_block_from_buffer(buf)) BufferNode;
-  }
-
-  // The following are the required conversion routines:
-  static BufferNode* make_node_from_buffer(void** buf) {
-    return (BufferNode*)make_block_from_buffer(buf);
-  }
+  // Return the buffer for node.
   static void** make_buffer_from_node(BufferNode *node) {
-    return make_buffer_from_block(node);
-  }
-  static void* make_block_from_node(BufferNode *node) {
-    return (void*)node;
-  }
-  static void** make_buffer_from_block(void* p) {
-    return (void**)((char*)p + aligned_size());
-  }
-  static void* make_block_from_buffer(void** p) {
-    return (void*)((char*)p - aligned_size());
+    // &_buffer[0] might lead to index out of bounds warnings.
+    return reinterpret_cast<void**>(
+      reinterpret_cast<char*>(node) + buffer_offset());
   }
 };