diff --git a/collector/kvm_bsd.c b/collector/kvm_bsd.c
new file mode 100644
index 0000000000..ad86d33e3a
--- /dev/null
+++ b/collector/kvm_bsd.c
@@ -0,0 +1,52 @@
+// Copyright 2017 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !nomeminfo
+// +build freebsd dragonfly
+
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdlib.h>
+
+int _kvm_swap_used_pages(uint64_t *out) {
+	const int total_only = 1; // from kvm_getswapinfo(3)
+
+	kvm_t *kd;
+	struct kvm_swap current;
+
+	kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL);
+	if (kd == NULL) {
+		return -1;
+	}
+
+	if (kvm_getswapinfo(kd, &current, total_only, 0) == -1) {
+		goto error1;
+	}
+
+	if (kvm_close(kd) != 0) {
+		return -1;
+	}
+	kd = NULL;
+
+	*out = current.ksw_used;
+	return 0;
+
+error1:
+	if (kd != NULL) {
+		kvm_close(kd);
+	}
+
+	return -1;
+}
diff --git a/collector/kvm_bsd.go b/collector/kvm_bsd.go
new file mode 100644
index 0000000000..b4e95e6a69
--- /dev/null
+++ b/collector/kvm_bsd.go
@@ -0,0 +1,42 @@
+// Copyright 2017 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !nomeminfo
+// +build freebsd dragonfly
+
+package collector
+
+import (
+	"fmt"
+	"sync"
+)
+
+// #cgo LDFLAGS: -lkvm
+// #include "kvm_bsd.h"
+import "C"
+
+type kvm struct {
+	mu     sync.Mutex
+	hasErr bool
+}
+
+func (k *kvm) SwapUsedPages() (value uint64, err error) {
+	k.mu.Lock()
+	defer k.mu.Unlock()
+	if C._kvm_swap_used_pages((*C.uint64_t)(&value)) == -1 {
+		k.hasErr = true
+		return 0, fmt.Errorf("couldn't get kvm stats")
+	}
+
+	return value, nil
+}
diff --git a/collector/kvm_bsd.h b/collector/kvm_bsd.h
new file mode 100644
index 0000000000..0cfbfa702e
--- /dev/null
+++ b/collector/kvm_bsd.h
@@ -0,0 +1,19 @@
+// Copyright 2017 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !nomeminfo
+// +build freebsd dragonfly
+
+#include <sys/types.h>
+
+int _kvm_swap_used_pages(uint64_t *out);
diff --git a/collector/meminfo.go b/collector/meminfo.go
index 68959efe35..ffe343a2e1 100644
--- a/collector/meminfo.go
+++ b/collector/meminfo.go
@@ -11,7 +11,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// +build darwin dragonfly freebsd linux openbsd
+// +build darwin linux openbsd
 // +build !nomeminfo
 
 package collector
diff --git a/collector/meminfo_bsd.go b/collector/meminfo_bsd.go
deleted file mode 100644
index d8eedb9692..0000000000
--- a/collector/meminfo_bsd.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2015 The Prometheus Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build freebsd dragonfly
-// +build !nomeminfo
-
-package collector
-
-import (
-	"fmt"
-
-	"golang.org/x/sys/unix"
-)
-
-func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {
-	info := make(map[string]float64)
-
-	tmp32, err := unix.SysctlUint32("vm.stats.vm.v_page_size")
-	if err != nil {
-		return nil, fmt.Errorf("sysctl(vm.stats.vm.v_page_size) failed: %s", err)
-	}
-	size := float64(tmp32)
-	fromPage := func(v float64) float64 {
-		return v * size
-	}
-
-	for _, ctl := range []bsdSysctl{
-		{name: "active_bytes", mib: "vm.stats.vm.v_active_count", conversion: fromPage},
-		{name: "inactive_bytes", mib: "vm.stats.vm.v_inactive_count", conversion: fromPage},
-		{name: "wired_bytes", mib: "vm.stats.vm.v_wire_count", conversion: fromPage},
-		{name: "cache_bytes", mib: "vm.stats.vm.v_cache_count", conversion: fromPage},
-		{name: "buffer_bytes", mib: "vfs.bufspace", dataType: bsdSysctlTypeCLong},
-		{name: "free_bytes", mib: "vm.stats.vm.v_free_count", conversion: fromPage},
-		{name: "size_bytes", mib: "vm.stats.vm.v_page_count", conversion: fromPage},
-		{name: "swap_in_bytes_total", mib: "vm.stats.vm.v_swappgsin", conversion: fromPage},
-		{name: "swap_out_bytes_total", mib: "vm.stats.vm.v_swappgsout", conversion: fromPage},
-		{name: "swap_size_bytes", mib: "vm.swap_total", dataType: bsdSysctlTypeUint64},
-	} {
-		v, err := ctl.Value()
-		if err != nil {
-			return nil, err
-		}
-
-		info[ctl.name] = v
-	}
-
-	return info, nil
-}
diff --git a/collector/memory_bsd.go b/collector/memory_bsd.go
new file mode 100644
index 0000000000..8c7265e362
--- /dev/null
+++ b/collector/memory_bsd.go
@@ -0,0 +1,158 @@
+// Copyright 2017 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build freebsd dragonfly
+// +build !nomeminfo
+
+package collector
+
+import (
+	"fmt"
+
+	"github.com/prometheus/client_golang/prometheus"
+	"golang.org/x/sys/unix"
+)
+
+const (
+	memorySubsystem = "memory"
+)
+
+type memoryCollector struct {
+	pageSize uint64
+	sysctls  []bsdSysctl
+	kvm      kvm
+}
+
+func init() {
+	registerCollector("meminfo", defaultEnabled, NewMemoryCollector)
+}
+
+// NewMemoryCollector returns a new Collector exposing memory stats.
+func NewMemoryCollector() (Collector, error) {
+	tmp32, err := unix.SysctlUint32("vm.stats.vm.v_page_size")
+	if err != nil {
+		return nil, fmt.Errorf("sysctl(vm.stats.vm.v_page_size) failed: %s", err)
+	}
+	size := float64(tmp32)
+
+	fromPage := func(v float64) float64 {
+		return v * size
+	}
+
+	return &memoryCollector{
+		pageSize: uint64(tmp32),
+		sysctls: []bsdSysctl{
+			// Descriptions via: https://wiki.freebsd.org/Memory
+			{
+				name:        "active_bytes",
+				description: "Recently used by userland",
+				mib:         "vm.stats.vm.v_active_count",
+				conversion:  fromPage,
+			},
+			{
+				name:        "inactive_bytes",
+				description: "Not recently used by userland",
+				mib:         "vm.stats.vm.v_inactive_count",
+				conversion:  fromPage,
+			},
+			{
+				name:        "wired_bytes",
+				description: "Locked in memory by kernel, mlock, etc",
+				mib:         "vm.stats.vm.v_wire_count",
+				conversion:  fromPage,
+			},
+			{
+				name:        "cache_bytes",
+				description: "Almost free, backed by swap or files, available for re-allocation",
+				mib:         "vm.stats.vm.v_cache_count",
+				conversion:  fromPage,
+			},
+			{
+				name:        "buffer_bytes",
+				description: "Disk IO Cache entries for non ZFS filesystems, only usable by kernel",
+				mib:         "vfs.bufspace",
+				dataType:    bsdSysctlTypeCLong,
+			},
+			{
+				name:        "free_bytes",
+				description: "Unallocated, available for allocation",
+				mib:         "vm.stats.vm.v_free_count",
+				conversion:  fromPage,
+			},
+			{
+				name:        "size_bytes",
+				description: "Total physical memory size",
+				mib:         "vm.stats.vm.v_page_count",
+				conversion:  fromPage,
+			},
+			{
+				name:        "swap_size_bytes",
+				description: "Total swap memory size",
+				mib:         "vm.swap_total",
+				dataType:    bsdSysctlTypeUint64,
+			},
+			// Descriptions via: top(1)
+			{
+				name:        "swap_in_bytes_total",
+				description: "Bytes paged in from swap devices",
+				mib:         "vm.stats.vm.v_swappgsin",
+				valueType:   prometheus.CounterValue,
+				conversion:  fromPage,
+			},
+			{
+				name:        "swap_out_bytes_total",
+				description: "Bytes paged out to swap devices",
+				mib:         "vm.stats.vm.v_swappgsout",
+				valueType:   prometheus.CounterValue,
+				conversion:  fromPage,
+			},
+		},
+	}, nil
+}
+
+// Update checks relevant sysctls for current memory usage, and kvm for swap
+// usage.
+func (c *memoryCollector) Update(ch chan<- prometheus.Metric) error {
+	for _, m := range c.sysctls {
+		v, err := m.Value()
+		if err != nil {
+			return fmt.Errorf("couldn't get memory: %s", err)
+		}
+
+		// Most are gauges.
+		if m.valueType == 0 {
+			m.valueType = prometheus.GaugeValue
+		}
+
+		ch <- prometheus.MustNewConstMetric(
+			prometheus.NewDesc(
+				prometheus.BuildFQName(namespace, memorySubsystem, m.name),
+				m.description,
+				nil, nil,
+			), m.valueType, v)
+	}
+
+	swapUsed, err := c.kvm.SwapUsedPages()
+	if err != nil {
+		return fmt.Errorf("couldn't get kvm: %s", err)
+	}
+
+	ch <- prometheus.MustNewConstMetric(
+		prometheus.NewDesc(
+			prometheus.BuildFQName(namespace, memorySubsystem, "swap_used_bytes"),
+			"Currently allocated swap",
+			nil, nil,
+		), prometheus.GaugeValue, float64(swapUsed*c.pageSize))
+
+	return nil
+}
