diff --git a/mediachanger/AcsProxyZmqSingleton.cpp b/mediachanger/AcsProxyZmqSingleton.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..572807d11ff7f314b479d6c415cc6bbe676beb93
--- /dev/null
+++ b/mediachanger/AcsProxyZmqSingleton.cpp
@@ -0,0 +1,60 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/exception/Exception.hpp"
+#include "common/utils/utils.hpp"
+#include "mediachanger/AcsProxyZmqSingleton.hpp"
+
+namespace cta {
+namespace mediachanger {
+
+//------------------------------------------------------------------------------
+// s_mutex
+//------------------------------------------------------------------------------
+std::mutex AcsProxyZmqSingleton::s_mutex;
+
+//------------------------------------------------------------------------------
+// s_instance
+//------------------------------------------------------------------------------
+std::unique_ptr<AcsProxyZmqSingleton> AcsProxyZmqSingleton::s_instance;
+
+//------------------------------------------------------------------------------
+// instance
+//------------------------------------------------------------------------------
+AcsProxyZmqSingleton &AcsProxyZmqSingleton::instance(void *const zmqContext) {
+  try {
+    std::lock_guard<std::mutex> lock(s_mutex);
+
+    if(nullptr == s_instance) {
+      s_instance.reset(new AcsProxyZmqSingleton(zmqContext));
+    }
+    return *s_instance;
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
+  }
+}
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+AcsProxyZmqSingleton::AcsProxyZmqSingleton(void *const zmqContext, const unsigned short serverPort) throw():
+  AcsProxyZmq(zmqContext, serverPort) {
+}
+
+} // namespace mediachanger
+} // namespace cta
diff --git a/mediachanger/AcsProxyZmqSingleton.hpp b/mediachanger/AcsProxyZmqSingleton.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c0dd110766bca35f6d331c3a1fab3571b6eeb094
--- /dev/null
+++ b/mediachanger/AcsProxyZmqSingleton.hpp
@@ -0,0 +1,95 @@
+/*
+ * The CERN Tape Archive(CTA) project
+ * Copyright(C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ *(at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "mediachanger/Constants.hpp"
+#include "mediachanger/AcsProxyZmq.hpp"
+
+#include <memory>
+#include <mutex>
+
+namespace cta {
+namespace mediachanger {
+
+/**
+ * A singleton class.
+ */
+class AcsProxyZmqSingleton: public AcsProxyZmq {
+public:
+
+  /**
+   * Delete the default constructor.
+   */
+  AcsProxyZmqSingleton() = delete;
+
+  /**
+   * Delete the copy constructor.
+   */
+  AcsProxyZmqSingleton(const AcsProxyZmqSingleton&) = delete;
+
+  /**
+   * Delete the move constructor.
+   */
+  AcsProxyZmqSingleton(AcsProxyZmqSingleton&&) = delete;
+
+  /**
+   * Delete the copy assignment oprator.
+   */
+  AcsProxyZmqSingleton &operator=(const AcsProxyZmqSingleton&) = delete;
+
+  /**
+   * Delete the move assignment oprator.
+   */
+  AcsProxyZmqSingleton &operator=(AcsProxyZmqSingleton&&) = delete;
+
+  /**
+   * Returns the singleton instance.
+   *
+   * @param zmqContext The ZMQ context to be used to construct the instance if
+   * the instance does not already exist.
+   * @return the singleton instance.
+   */
+  static AcsProxyZmqSingleton &instance(void *const zmqContext);
+
+private:
+
+  /**
+   * Provate constructor to only be used by the instance() method.
+   *
+   * @param zmqContext The ZMQ context.
+   * @param serverPort The TCP/IP port on which the CASTOR ACS daemon is
+   * listening for ZMQ messages.
+   */
+  AcsProxyZmqSingleton(void *const zmqContext, const unsigned short serverPort = ACS_PORT) throw();
+
+  /**
+   * Mutex used to implement a critical region around the implementation of the
+   * instance() method.
+   */
+  static std::mutex s_mutex;
+
+  /**
+   * The single instance.
+   */
+  static std::unique_ptr<AcsProxyZmqSingleton> s_instance;
+
+}; // class AcsProxyZmqSingleton
+
+} // namespace mediachanger
+} // namespace cta
diff --git a/mediachanger/CMakeLists.txt b/mediachanger/CMakeLists.txt
index 72358c7e49018bbcecb5446295253dee7c2cc561..4059ee0ff56db329d21cf51a8ada6769db27d909 100644
--- a/mediachanger/CMakeLists.txt
+++ b/mediachanger/CMakeLists.txt
@@ -25,6 +25,7 @@ PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles})
 set (MEDIACHANGER_LIB_SRC_FILES
   AcsLibrarySlot.cpp
   AcsProxyZmq.cpp
+  AcsProxyZmqSingleton.cpp
   CmdLine.cpp
   CmdLineTool.cpp
   CommonMarshal.cpp
diff --git a/mediachanger/MediaChangerFacade.cpp b/mediachanger/MediaChangerFacade.cpp
index 172aaf2ab74f4b08a6e263a33d41692532b11c7b..9322d4163a7e39eee2bae4b62a3516d5b2b514f7 100644
--- a/mediachanger/MediaChangerFacade.cpp
+++ b/mediachanger/MediaChangerFacade.cpp
@@ -17,12 +17,8 @@
  */
 
 #include "common/exception/Exception.hpp"
-#include "common/make_unique.hpp"
-#include "mediachanger/AcsProxyZmq.hpp"
-#include "mediachanger/Constants.hpp"
+#include "mediachanger/AcsProxyZmqSingleton.hpp"
 #include "mediachanger/MediaChangerFacade.hpp"
-#include "mediachanger/MmcProxyLog.hpp"
-#include "mediachanger/RmcProxyTcpIp.hpp"
 
 namespace cta {
 namespace mediachanger {
@@ -31,8 +27,8 @@ namespace mediachanger {
 // constructor
 //------------------------------------------------------------------------------
 MediaChangerFacade::MediaChangerFacade(log::Logger &log, void *const zmqContext) throw():
-  m_log(log),
-  m_zmqContext(zmqContext) {
+  m_zmqContext(zmqContext),
+  m_mmcProxy(log) {
 }
 
 //------------------------------------------------------------------------------
@@ -40,7 +36,7 @@ MediaChangerFacade::MediaChangerFacade(log::Logger &log, void *const zmqContext)
 //------------------------------------------------------------------------------
 void MediaChangerFacade::mountTapeReadOnly(const std::string &vid, const LibrarySlot &slot) {
   try {
-    return createMediaChangerProxy(slot.getLibraryType())->mountTapeReadOnly(vid, slot);
+    return getProxy(slot.getLibraryType()).mountTapeReadOnly(vid, slot);
   } catch(cta::exception::Exception &ne) {
     cta::exception::Exception ex;
     ex.getMessage() << "Failed to mount tape for read-only access: vid=" << vid << " slot=" << slot.str() << ": " <<
@@ -54,7 +50,7 @@ void MediaChangerFacade::mountTapeReadOnly(const std::string &vid, const Library
 //------------------------------------------------------------------------------
 void MediaChangerFacade::mountTapeReadWrite(const std::string &vid, const LibrarySlot &slot) {
   try {
-    return createMediaChangerProxy(slot.getLibraryType())->mountTapeReadWrite(vid, slot);
+    return getProxy(slot.getLibraryType()).mountTapeReadWrite(vid, slot);
   } catch(cta::exception::Exception &ne) {
     cta::exception::Exception ex;
     ex.getMessage() << "Failed to mount tape for read/write access: vid=" << vid << " slot=" << slot.str() << ": " <<
@@ -68,7 +64,7 @@ void MediaChangerFacade::mountTapeReadWrite(const std::string &vid, const Librar
 //------------------------------------------------------------------------------
 void MediaChangerFacade::dismountTape(const std::string &vid, const LibrarySlot &slot) {
   try {
-    return createMediaChangerProxy(slot.getLibraryType())->dismountTape(vid, slot);
+    return getProxy(slot.getLibraryType()).dismountTape(vid, slot);
   } catch(cta::exception::Exception &ne) {
     cta::exception::Exception ex;
     ex.getMessage() << "Failed to dismount tape: vid=" << vid << " slot=" << slot.str() << ": " <<
@@ -82,7 +78,7 @@ void MediaChangerFacade::dismountTape(const std::string &vid, const LibrarySlot
 //------------------------------------------------------------------------------
 void MediaChangerFacade::forceDismountTape(const std::string &vid, const LibrarySlot &slot) {
   try {
-    return createMediaChangerProxy(slot.getLibraryType())->forceDismountTape(vid, slot);
+    return getProxy(slot.getLibraryType()).forceDismountTape(vid, slot);
   } catch(cta::exception::Exception &ne) {
     cta::exception::Exception ex;
     ex.getMessage() << "Failed to force dismount tape: vid=" << vid << " slot=" << slot.str() << ": " <<
@@ -92,17 +88,22 @@ void MediaChangerFacade::forceDismountTape(const std::string &vid, const Library
 }
 
 //------------------------------------------------------------------------------
-// createMediaChangerProxy
+// getProxy
 //------------------------------------------------------------------------------
-std::unique_ptr<MediaChangerProxy> MediaChangerFacade::createMediaChangerProxy(const TapeLibraryType libraryType) {
+MediaChangerProxy &MediaChangerFacade::getProxy(const TapeLibraryType libraryType) {
   try {
     switch(libraryType) {
     case TAPE_LIBRARY_TYPE_ACS:
-      return make_unique<AcsProxyZmq>(m_zmqContext);
+      // Using AcsProxyZmqSingleton instead of simply having a AcsProxyZmq
+      // member variable (e.g. m_acsProxy) in order to only instantiate an
+      // AcsProxyZmq object if necessary.  Instantiating such as object
+      // results in a one off memory leak related to ZMQ that would cause
+      // valgrind to fail on simple CTA unit-tests.
+      return AcsProxyZmqSingleton::instance(m_zmqContext);
     case TAPE_LIBRARY_TYPE_MANUAL:
-      return make_unique<MmcProxyLog>(m_log);
+      return m_mmcProxy;
     case TAPE_LIBRARY_TYPE_SCSI:
-      return make_unique<RmcProxyTcpIp>();
+      return m_rmcProxy;
     default:
       // Should never get here
       throw exception::Exception("Library slot has an unexpected library type");
diff --git a/mediachanger/MediaChangerFacade.hpp b/mediachanger/MediaChangerFacade.hpp
index 372bc76fed676c6f03fe4e93ab9d2c54b53699b0..f2e918d3aca14b5150eb7e09492ec013c62e0787 100644
--- a/mediachanger/MediaChangerFacade.hpp
+++ b/mediachanger/MediaChangerFacade.hpp
@@ -21,6 +21,8 @@
 #include "common/log/Logger.hpp"
 #include "mediachanger/LibrarySlot.hpp"
 #include "mediachanger/MediaChangerProxy.hpp"
+#include "mediachanger/MmcProxyLog.hpp"
+#include "mediachanger/RmcProxyTcpIp.hpp"
 #include "mediachanger/ZmqContextSingleton.hpp"
 
 #include <memory>
@@ -38,10 +40,13 @@ public:
   /**
    * Constructor.
    *
-   * @param log Object representing the API to the CTA logging system.
+   * @param log Object representing the API to the CTA logging system.  This log
+   * object will be used by the manual media changer to communicate with the
+   * tape operator.
    * @param zmqContext The ZMQ context.  There is usually one ZMQ context within
    * a program.  Set this parameter in order for the MediaChangerFacade to share
-   * an already existing ZMQ context.
+   * an already existing ZMQ context.  If this parameter is not set then the
+   * ZmqContextSingleton of the mediachanger namespace will be used.
    */
   MediaChangerFacade(log::Logger &log, void *const zmqContext = ZmqContextSingleton::instance()) throw();
 
@@ -91,22 +96,24 @@ public:
 private:
 
   /**
-   * Object representing the API to the CTA logging system.
+   * The ZMQ context.
    */
-  log::Logger &m_log;
+  void *m_zmqContext;
 
   /**
-   * The ZMQ context.
+   * Manual media changer proxy.
    */
-  void *m_zmqContext;
+  MmcProxyLog m_mmcProxy;
 
   /**
-   * Factory method that creates a media changer proxy object based on the
-   * specified tape library type.
-   *
-   * @param libraryType The type of tape library.
+   * SCSI media changer proxy.
+   */
+  RmcProxyTcpIp m_rmcProxy;
+
+  /**
+   * Returns the media changer proxy for the specified library type.
    */
-  std::unique_ptr<MediaChangerProxy> createMediaChangerProxy(const TapeLibraryType libraryType);
+  MediaChangerProxy &getProxy(const TapeLibraryType libraryType);
 
 }; // class MediaChangerFacade