← Back to Module 4
Memory Optimization
Memory Leak Prevention
Common Memory Leaks
// 1. Static Collections
public class MemoryLeakExample {
private static List<Object> list = new ArrayList<>();
public void addObject(Object obj) {
list.add(obj); // Objects never removed
}
}
// 2. Unclosed Resources
public class ResourceLeak {
public void readFile() {
FileInputStream fis = new FileInputStream("file.txt");
// Resource not closed
}
}
// 3. Event Listener Leaks
public class EventLeak {
private List<EventListener> listeners = new ArrayList<>();
public void addListener(EventListener listener) {
listeners.add(listener);
// Listener never removed
}
}
Prevention Techniques
// 1. Use try-with-resources
public void readFile() {
try (FileInputStream fis = new FileInputStream("file.txt")) {
// Use the resource
} catch (IOException e) {
e.printStackTrace();
}
}
// 2. Clear collections when no longer needed
public void cleanup() {
list.clear();
}
// 3. Remove event listeners
public void removeListener(EventListener listener) {
listeners.remove(listener);
}
Memory-Efficient Data Structures
Collection Types
// 1. ArrayList vs LinkedList
// ArrayList: Better for random access, less memory overhead
ArrayList<String> arrayList = new ArrayList<>();
// LinkedList: Better for insertions/deletions, more memory overhead
LinkedList<String> linkedList = new LinkedList<>();
// 2. HashMap vs TreeMap
// HashMap: Better performance, unordered
HashMap<String, Integer> hashMap = new HashMap<>();
// TreeMap: Ordered, more memory overhead
TreeMap<String, Integer> treeMap = new TreeMap<>();
// 3. HashSet vs TreeSet
// HashSet: Better performance, unordered
HashSet<String> hashSet = new HashSet<>();
// TreeSet: Ordered, more memory overhead
TreeSet<String> treeSet = new TreeSet<>();
Primitive vs Wrapper Types
// Use primitive types when possible
int number = 42; // 4 bytes
Integer wrappedNumber = 42; // 16 bytes + overhead
// Use primitive arrays for large datasets
int[] numbers = new int[1000]; // 4000 bytes
Integer[] wrappedNumbers = new Integer[1000]; // 16000 bytes + overhead
String Optimization
String Creation
// 1. String Literals (String Pool)
String s1 = "Hello"; // Uses string pool
String s2 = "Hello"; // Reuses same object
// 2. String Constructor
String s3 = new String("Hello"); // Creates new object
String s4 = new String("Hello"); // Creates another object
// 3. StringBuilder for concatenation
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("Hello");
}
String result = sb.toString();
String Memory Management
// 1. Use intern() for frequently used strings
String s1 = "Hello".intern();
String s2 = "Hello".intern(); // Same object
// 2. Use String.format() for complex strings
String formatted = String.format("Hello %s, you are %d years old", name, age);
// 3. Use String.join() for collections
String joined = String.join(", ", list);
Large Object Handling
Stream Processing
// Process large files without loading into memory
try (BufferedReader reader = new BufferedReader(new FileReader("large.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
processLine(line);
}
}
// Process large collections using streams
List<String> result = largeList.stream()
.filter(s -> s.length() > 5)
.map(String::toUpperCase)
.collect(Collectors.toList());
Memory-Mapped Files
// Use memory-mapped files for large datasets
try (FileChannel channel = FileChannel.open(Paths.get("large.dat"))) {
MappedByteBuffer buffer = channel.map(
FileChannel.MapMode.READ_ONLY, 0, channel.size());
// Process buffer
}
Memory Profiling
Profiling Tools
- JProfiler: Comprehensive profiling tool
- VisualVM: Built-in Java profiling tool
- Eclipse MAT: Memory analyzer tool
- Java Flight Recorder: Low-overhead profiling
Heap Analysis
// Enable heap dump on OOM
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dump
// Enable detailed GC logging
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:gc.log