Python中类与普通变量的内存使用差异及优化问询
Hey there! Let's unpack what's going on with your memory usage tests and how to address your concerns as a Java developer transitioning to Python.
First, a critical clarification about your memory measurement
Your test uses resource.getrusage().ru_maxrss, which returns the maximum resident memory size your process has used since it started—not the current memory usage at the time of the call. That's why your later tests all show the same 80195584 value: it's the peak memory hit during the earlier int_replace_test, and subsequent tests never exceeded that peak. This means your initial conclusion about "old memory not being released" might be off-base.
To get accurate current memory usage for each test, use a tool like psutil instead:
import psutil import os def get_current_rss(): return psutil.Process(os.getpid()).memory_info().rss
Replace your resource calls with this function, and you'll see the actual memory changes during each test.
Why the class-based tests showed higher peak memory
When you work with a class instance:
- The instance holds a reference to the
sampleinteger object for the duration of the test. For large integers (like the sum of 1 to 1e6), this object takes up more memory, and it stays in memory until the instance is garbage-collected. - Method calls also create small temporary stack frames, but these are usually cleaned up quickly by Python's garbage collector.
In contrast, when you use a simple variable:
- After the loop ends, the large integer is no longer referenced (once you print it, unless you keep the variable around), so the GC can reclaim that memory immediately. But since
ru_maxrsstracks peaks, you wouldn't see this drop in your original output.
Fixes for memory efficiency in your class-based code
Since you need to use classes to manage multiple variables, here are actionable optimizations:
- Use
__slots__to reduce instance memory overhead
Python instances have a default__dict__to store attributes, which uses extra memory. By defining__slots__, you disable this dict and specify exactly which attributes your class will have, cutting down memory usage significantly (especially if you create many instances):
class Sample: __slots__ = ['sample'] # Explicitly declare attributes def __init__(self): self.sample = 0 def increase(self, amt): self.sample += amt def replace(self, amt): self.sample = amt
Verify there are no unintended references
Make sure your actual code isn't holding onto old objects in other attributes (e.g., lists, dictionaries that accumulate values). If you have collections that grow indefinitely, those will cause real memory bloat—clean them up when they're no longer needed.Test with
tracemallocto pinpoint leaks
If you suspect a real memory leak, use Python's built-intracemallocto track exactly where memory is being allocated:
import tracemalloc tracemalloc.start() int_test() # Run your function snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') print("\nTop memory allocations:") for stat in top_stats[:5]: print(stat)
This will show you which lines are creating the most memory-heavy objects.
Final note for Java devs
Python's garbage collection is automatic, but it works differently from Java's. You rarely need to manually trigger it, but understanding reference counts and avoiding unnecessary object retention is key. For most cases, the class-based approach won't cause memory leaks—your initial test results were skewed by the peak memory measurement.
内容的提问来源于stack exchange,提问作者william

