Skip to content

Commit ef8682b

Browse files
darguetawillmcgugan
authored andcommitted
[MemFS] Release memory when close() is called (#313)
* Release memory after closing the file system. * Modified CHANGELOG.rst and CONTRIBUTORS.rst * PR feedback * Apparently this list is alphabetized?
1 parent 37b46b4 commit ef8682b

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## [2.4.9] - (Unreleased)
9+
10+
### Changed
11+
12+
- `MemFS` now immediately releases all memory it holds when `close()` is called,
13+
rather than when it gets garbage collected. Closes [issue #308](https://github.com/PyFilesystem/pyfilesystem2/issues/308).
14+
815
## [2.4.8] - 2019-06-12
916

1017
### Changed

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Many thanks to the following developers for contributing to this project:
44

5+
- [Diego Argueta](https://github.com/dargueta)
56
- [Geoff Jukes](https://github.com/geoffjukes)
67
- [Giampaolo](https://github.com/gpcimino)
78
- [Martin Larralde](https://github.com/althonos)

fs/memoryfs.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@ def _get_dir_entry(self, dir_path):
340340
current_entry = current_entry.get_entry(path_component)
341341
return current_entry
342342

343+
def close(self):
344+
# type: () -> None
345+
self.root = None
346+
return super(MemoryFS, self).close()
347+
343348
def getinfo(self, path, namespaces=None):
344349
# type: (Text, Optional[Collection[Text]]) -> Info
345350
namespaces = namespaces or ()

tests/test_memoryfs.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,68 @@
11
from __future__ import unicode_literals
22

3+
import posixpath
34
import unittest
45

56
from fs import memoryfs
67
from fs.test import FSTestCases
8+
from fs.test import UNICODE_TEXT
9+
10+
try:
11+
# Only supported on Python 3.4+
12+
import tracemalloc
13+
except ImportError:
14+
tracemalloc = None
715

816

917
class TestMemoryFS(FSTestCases, unittest.TestCase):
1018
"""Test OSFS implementation."""
1119

1220
def make_fs(self):
1321
return memoryfs.MemoryFS()
22+
23+
def _create_many_files(self):
24+
for parent_dir in {"/", "/one", "/one/two", "/one/other-two/three"}:
25+
self.fs.makedirs(parent_dir, recreate=True)
26+
for file_id in range(50):
27+
self.fs.writetext(
28+
posixpath.join(parent_dir, str(file_id)), UNICODE_TEXT
29+
)
30+
31+
@unittest.skipIf(
32+
not tracemalloc, "`tracemalloc` isn't supported on this Python version."
33+
)
34+
def test_close_mem_free(self):
35+
"""Ensure all file memory is freed when calling close().
36+
37+
Prevents regression against issue #308.
38+
"""
39+
trace_filters = [tracemalloc.Filter(True, "*/memoryfs.py")]
40+
tracemalloc.start()
41+
42+
before = tracemalloc.take_snapshot().filter_traces(trace_filters)
43+
self._create_many_files()
44+
after_create = tracemalloc.take_snapshot().filter_traces(trace_filters)
45+
46+
self.fs.close()
47+
after_close = tracemalloc.take_snapshot().filter_traces(trace_filters)
48+
tracemalloc.stop()
49+
50+
[diff_create] = after_create.compare_to(
51+
before, key_type="filename", cumulative=True
52+
)
53+
self.assertGreater(
54+
diff_create.size_diff,
55+
0,
56+
"Memory usage didn't increase after creating files; diff is %0.2f KiB."
57+
% (diff_create.size_diff / 1024.0),
58+
)
59+
60+
[diff_close] = after_close.compare_to(
61+
after_create, key_type="filename", cumulative=True
62+
)
63+
self.assertLess(
64+
diff_close.size_diff,
65+
0,
66+
"Memory usage increased after closing the file system; diff is %0.2f KiB."
67+
% (diff_close.size_diff / 1024.0),
68+
)

0 commit comments

Comments
 (0)