diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp
index dde620e9398..1b2b883f71a 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp
@@ -56,26 +56,6 @@ G1ConcurrentMarkThread::G1ConcurrentMarkThread(G1ConcurrentMark* cm) :
   create_and_start();
 }
 
-class CMRemark : public VoidClosure {
-  G1ConcurrentMark* _cm;
-public:
-  CMRemark(G1ConcurrentMark* cm) : _cm(cm) {}
-
-  void do_void(){
-    _cm->remark();
-  }
-};
-
-class CMCleanup : public VoidClosure {
-  G1ConcurrentMark* _cm;
-public:
-  CMCleanup(G1ConcurrentMark* cm) : _cm(cm) {}
-
-  void do_void(){
-    _cm->cleanup();
-  }
-};
-
 double G1ConcurrentMarkThread::mmu_delay_end(G1Policy* policy, bool remark) {
   // There are 3 reasons to use SuspendibleThreadSetJoiner.
   // 1. To avoid concurrency problem.
@@ -239,8 +219,7 @@ bool G1ConcurrentMarkThread::subphase_delay_to_keep_mmu_before_remark() {
 
 bool G1ConcurrentMarkThread::subphase_remark() {
   ConcurrentGCBreakpoints::at("BEFORE MARKING COMPLETED");
-  CMRemark cl(_cm);
-  VM_G1Concurrent op(&cl, "Pause Remark");
+  VM_G1PauseRemark op;
   VMThread::execute(&op);
   return _cm->has_aborted();
 }
@@ -257,8 +236,7 @@ bool G1ConcurrentMarkThread::phase_delay_to_keep_mmu_before_cleanup() {
 }
 
 bool G1ConcurrentMarkThread::phase_cleanup() {
-  CMCleanup cl(_cm);
-  VM_G1Concurrent op(&cl, "Pause Cleanup");
+  VM_G1PauseCleanup op;
   VMThread::execute(&op);
   return _cm->has_aborted();
 }
diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp
index 75d209b94a5..94699a0c718 100644
--- a/src/hotspot/share/gc/g1/g1VMOperations.cpp
+++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp
@@ -170,7 +170,7 @@ void VM_G1CollectForAllocation::doit() {
   }
 }
 
-void VM_G1Concurrent::doit() {
+void VM_G1PauseConcurrent::doit() {
   GCIdMark gc_id_mark(_gc_id);
   GCTraceCPUTime tcpu;
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
@@ -184,17 +184,28 @@ void VM_G1Concurrent::doit() {
   TraceCollectorStats tcs(g1h->monitoring_support()->conc_collection_counters());
   SvcGCMarker sgcm(SvcGCMarker::CONCURRENT);
   IsGCActiveMark x;
-  _cl->do_void();
+
+  work();
 }
 
-bool VM_G1Concurrent::doit_prologue() {
+bool VM_G1PauseConcurrent::doit_prologue() {
   Heap_lock->lock();
   return true;
 }
 
-void VM_G1Concurrent::doit_epilogue() {
+void VM_G1PauseConcurrent::doit_epilogue() {
   if (Universe::has_reference_pending_list()) {
     Heap_lock->notify_all();
   }
   Heap_lock->unlock();
 }
+
+void VM_G1PauseRemark::work() {
+  G1CollectedHeap* g1h = G1CollectedHeap::heap();
+  g1h->concurrent_mark()->remark();
+}
+
+void VM_G1PauseCleanup::work() {
+  G1CollectedHeap* g1h = G1CollectedHeap::heap();
+  g1h->concurrent_mark()->cleanup();
+}
diff --git a/src/hotspot/share/gc/g1/g1VMOperations.hpp b/src/hotspot/share/gc/g1/g1VMOperations.hpp
index b5f36a51b78..72f450ad3bc 100644
--- a/src/hotspot/share/gc/g1/g1VMOperations.hpp
+++ b/src/hotspot/share/gc/g1/g1VMOperations.hpp
@@ -87,18 +87,33 @@ private:
 };
 
 // Concurrent G1 stop-the-world operations such as remark and cleanup.
-class VM_G1Concurrent : public VM_Operation {
-  VoidClosure* _cl;
-  const char*  _message;
+class VM_G1PauseConcurrent : public VM_Operation {
   uint         _gc_id;
+  const char*  _message;
+
+protected:
+  VM_G1PauseConcurrent(const char* message) :
+    _gc_id(GCId::current()), _message(message) { }
+  virtual void work() = 0;
 
 public:
-  VM_G1Concurrent(VoidClosure* cl, const char* message) :
-    _cl(cl), _message(message), _gc_id(GCId::current()) { }
-  virtual VMOp_Type type() const { return VMOp_G1Concurrent; }
-  virtual void doit();
-  virtual bool doit_prologue();
-  virtual void doit_epilogue();
+  bool doit_prologue() override;
+  void doit_epilogue() override;
+  void doit() override;
+};
+
+class VM_G1PauseRemark : public VM_G1PauseConcurrent {
+public:
+  VM_G1PauseRemark() : VM_G1PauseConcurrent("Pause Remark") { }
+  VMOp_Type type() const override { return VMOp_G1PauseRemark; }
+  void work() override;
+};
+
+class VM_G1PauseCleanup : public VM_G1PauseConcurrent {
+public:
+  VM_G1PauseCleanup() : VM_G1PauseConcurrent("Pause Cleanup") { }
+  VMOp_Type type() const override { return VMOp_G1PauseCleanup; }
+  void work() override;
 };
 
 #endif // SHARE_GC_G1_G1VMOPERATIONS_HPP
diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp
index 28507aba7c7..c872ee11d3c 100644
--- a/src/hotspot/share/runtime/vmOperation.hpp
+++ b/src/hotspot/share/runtime/vmOperation.hpp
@@ -58,7 +58,8 @@
   template(ParallelGCSystemGC)                    \
   template(G1CollectForAllocation)                \
   template(G1CollectFull)                         \
-  template(G1Concurrent)                          \
+  template(G1PauseRemark)                         \
+  template(G1PauseCleanup)                        \
   template(G1TryInitiateConcMark)                 \
   template(ZMarkStart)                            \
   template(ZMarkEnd)                              \