Skip to content

Bellek Etkin UI Yönetimi

Mobil cihazlarda sınırlı bellek kaynaklarının verimli kullanılması, uygulamanın performansı ve kullanıcı deneyimi açısından kritik öneme sahiptir. Bu bölümde bellek sızıntılarını önleme, etkin bellek yönetimi ve optimize edilmiş veri yapıları ele alınacaktır.

Bellek Yönetimi Temelleri

Memory Leaks'i Önleme

kotlin
// Android - WeakReference kullanarak memory leak'leri önleme
class MemoryEfficientActivity : AppCompatActivity() {
    private var asyncTask: WeakReference<BackgroundTask>? = null
    private lateinit var viewModel: MainViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ViewModel kullanarak configuration changes'e karşı koruma
        viewModel = ViewModelProvider(this)[MainViewModel::class.java]
        
        // Weak reference ile task referansı
        val task = BackgroundTask(WeakReference(this))
        asyncTask = WeakReference(task)
        task.execute()
    }
    
    override fun onDestroy() {
        super.onDestroy()
        
        // AsyncTask'i iptal et
        asyncTask?.get()?.cancel(true)
        asyncTask = null
        
        // Event listener'ları temizle
        EventBus.getDefault().unregister(this)
        
        // Bitmap'leri recycle et
        recycleBitmaps()
    }
    
    private fun recycleBitmaps() {
        // ImageView'lardaki bitmap'leri temizle
        findViewById<ImageView>(R.id.imageView)?.setImageDrawable(null)
        
        // Cache'deki bitmap'leri temizle
        Glide.get(this).clearMemory()
    }
}

// WeakReference ile güvenli callback
class BackgroundTask(
    private val activityRef: WeakReference<MemoryEfficientActivity>
) : AsyncTask<Void, Void, String>() {
    
    override fun doInBackground(vararg params: Void?): String {
        // Ağır işlem
        Thread.sleep(5000)
        return "Tamamlandı"
    }
    
    override fun onPostExecute(result: String?) {
        val activity = activityRef.get()
        if (activity != null && !activity.isDestroyed) {
            // UI güncelleme güvenli
            activity.updateUI(result)
        }
    }
}

// Memory-efficient ViewHolder pattern
class OptimizedViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    private val titleView: TextView = itemView.findViewById(R.id.title)
    private val imageView: ImageView = itemView.findViewById(R.id.image)
    
    fun bind(item: DataItem) {
        titleView.text = item.title
        
        // Glide ile bellek etkin image loading
        Glide.with(itemView.context)
            .load(item.imageUrl)
            .diskCacheStrategy(DiskCacheStrategy.ALL)
            .override(200, 200) // Boyut sınırla
            .centerCrop()
            .into(imageView)
    }
    
    fun recycle() {
        // ViewHolder yeniden kullanılırken temizlik
        Glide.with(itemView.context).clear(imageView)
        titleView.text = null
    }
}

iOS Memory Management

swift
// iOS - ARC ve weak references
class MemoryEfficientViewController: UIViewController {
    private weak var delegate: ViewControllerDelegate?
    private var observations: [NSKeyValueObservation] = []
    private var notificationTokens: [NSObjectProtocol] = []
    
    // Strong reference cycle'ları önlemek için weak self kullanımı
    private func setupNetworking() {
        NetworkManager.shared.fetchData { [weak self] result in
            guard let self = self else { return }
            
            DispatchQueue.main.async {
                self.handleNetworkResult(result)
            }
        }
    }
    
    // Timer ile memory leak'i önleme
    private func setupTimer() {
        let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            self?.updateUI()
        }
        
        // View controller deallocate olduğunda timer'ı invalidate et
        timer.tolerance = 0.1
    }
    
    // KVO observations temizleme
    private func setupObservations() {
        let observation = observe(\.view.bounds) { [weak self] _, _ in
            self?.handleBoundsChange()
        }
        observations.append(observation)
    }
    
    // Notification observers temizleme
    private func setupNotifications() {
        let token = NotificationCenter.default.addObserver(
            forName: .UIApplicationDidEnterBackground,
            object: nil,
            queue: .main
        ) { [weak self] _ in
            self?.handleBackgroundTransition()
        }
        notificationTokens.append(token)
    }
    
    deinit {
        // Tüm observations'ı temizle
        observations.forEach { $0.invalidate() }
        observations.removeAll()
        
        // Notification observers'ı temizle
        notificationTokens.forEach {
            NotificationCenter.default.removeObserver($0)
        }
        notificationTokens.removeAll()
        
        print("ViewController successfully deallocated")
    }
}

// Memory-efficient image caching
class ImageCacheManager {
    private let memoryCache = NSCache<NSString, UIImage>()
    private let diskCache: DiskCache
    
    init() {
        // Memory cache configuration
        memoryCache.countLimit = 50
        memoryCache.totalCostLimit = 50 * 1024 * 1024 // 50MB
        
        // Disk cache setup
        diskCache = DiskCache(name: "ImageCache")
        
        // Memory warning'de cache'i temizle
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(clearMemoryCache),
            name: UIApplication.didReceiveMemoryWarningNotification,
            object: nil
        )
    }
    
    @objc private func clearMemoryCache() {
        memoryCache.removeAllObjects()
    }
    
    func loadImage(from url: URL, completion: @escaping (UIImage?) -> Void) {
        let key = url.absoluteString as NSString
        
        // Memory cache'de var mı kontrol et
        if let cachedImage = memoryCache.object(forKey: key) {
            completion(cachedImage)
            return
        }
        
        // Disk cache'de var mı kontrol et
        diskCache.object(forKey: url.absoluteString) { [weak self] image in
            if let image = image {
                self?.memoryCache.setObject(image, forKey: key)
                DispatchQueue.main.async {
                    completion(image)
                }
                return
            }
            
            // Network'ten yükle
            self?.downloadImage(from: url) { downloadedImage in
                if let image = downloadedImage {
                    self?.memoryCache.setObject(image, forKey: key)
                    self?.diskCache.setObject(image, forKey: url.absoluteString)
                }
                
                DispatchQueue.main.async {
                    completion(downloadedImage)
                }
            }
        }
    }
}

Flutter Memory Optimization

dart
// Flutter - Widget'ların efficient disposal'ı
class MemoryEfficientWidget extends StatefulWidget {
  @override
  _MemoryEfficientWidgetState createState() => _MemoryEfficientWidgetState();
}

class _MemoryEfficientWidgetState extends State<MemoryEfficientWidget> {
  StreamSubscription? _streamSubscription;
  Timer? _timer;
  AnimationController? _animationController;
  late ScrollController _scrollController;
  
  @override
  void initState() {
    super.initState();
    
    _scrollController = ScrollController();
    
    // Stream subscription
    _streamSubscription = DataStream.listen((data) {
      if (mounted) {
        setState(() {
          // Update UI
        });
      }
    });
    
    // Timer setup
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      if (mounted) {
        updatePeriodicData();
      }
    });
    
    // Animation controller
    _animationController = AnimationController(
      duration: Duration(milliseconds: 300),
      vsync: this,
    );
  }
  
  @override
  void dispose() {
    // Stream subscription'ı iptal et
    _streamSubscription?.cancel();
    _streamSubscription = null;
    
    // Timer'ı iptal et
    _timer?.cancel();
    _timer = null;
    
    // Animation controller'ı dispose et
    _animationController?.dispose();
    _animationController = null;
    
    // Scroll controller'ı dispose et
    _scrollController.dispose();
    
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        controller: _scrollController,
        itemBuilder: (context, index) {
          // AutomaticKeepAliveClientMixin yerine manuel optimizasyon
          return MemoryEfficientListItem(
            key: ValueKey('item_$index'),
            data: items[index],
          );
        },
      ),
    );
  }
}

// Memory-efficient list item
class MemoryEfficientListItem extends StatelessWidget {
  final ItemData data;
  
  const MemoryEfficientListItem({
    Key? key,
    required this.data,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      child: Card(
        child: ListTile(
          leading: OptimizedNetworkImage(
            url: data.imageUrl,
            width: 50,
            height: 50,
          ),
          title: Text(data.title),
          subtitle: Text(data.description),
        ),
      ),
    );
  }
}

// Memory-efficient image widget
class OptimizedNetworkImage extends StatefulWidget {
  final String url;
  final double width;
  final double height;
  
  const OptimizedNetworkImage({
    Key? key,
    required this.url,
    required this.width,
    required this.height,
  }) : super(key: key);
  
  @override
  _OptimizedNetworkImageState createState() => _OptimizedNetworkImageState();
}

class _OptimizedNetworkImageState extends State<OptimizedNetworkImage> {
  @override
  Widget build(BuildContext context) {
    return Image.network(
      widget.url,
      width: widget.width,
      height: widget.height,
      fit: BoxFit.cover,
      // Memory cache optimization
      cacheWidth: widget.width.toInt(),
      cacheHeight: widget.height.toInt(),
      // Error handling
      errorBuilder: (context, error, stackTrace) {
        return Container(
          width: widget.width,
          height: widget.height,
          color: Colors.grey[300],
          child: Icon(Icons.error),
        );
      },
      // Loading placeholder
      loadingBuilder: (context, child, loadingProgress) {
        if (loadingProgress == null) return child;
        
        return Container(
          width: widget.width,
          height: widget.height,
          child: CircularProgressIndicator(
            value: loadingProgress.expectedTotalBytes != null
                ? loadingProgress.cumulativeBytesLoaded /
                  loadingProgress.expectedTotalBytes!
                : null,
          ),
        );
      },
    );
  }
}

Object Pooling ve Caching

Object Pool Implementation

javascript
// React Native - Object pooling pattern
class ObjectPool {
  constructor(createFn, resetFn, maxSize = 50) {
    this.createFn = createFn;
    this.resetFn = resetFn;
    this.maxSize = maxSize;
    this.pool = [];
    this.usedObjects = new Set();
  }
  
  acquire() {
    let obj;
    
    if (this.pool.length > 0) {
      obj = this.pool.pop();
    } else {
      obj = this.createFn();
    }
    
    this.usedObjects.add(obj);
    return obj;
  }
  
  release(obj) {
    if (!this.usedObjects.has(obj)) {
      return; // Already released or not from this pool
    }
    
    this.usedObjects.delete(obj);
    
    if (this.resetFn) {
      this.resetFn(obj);
    }
    
    if (this.pool.length < this.maxSize) {
      this.pool.push(obj);
    }
  }
  
  clear() {
    this.pool.length = 0;
    this.usedObjects.clear();
  }
  
  getStats() {
    return {
      poolSize: this.pool.length,
      usedCount: this.usedObjects.size,
      totalCreated: this.pool.length + this.usedObjects.size
    };
  }
}

// List item pool example
const ListItemPool = new ObjectPool(
  // Create function
  () => ({
    id: null,
    title: '',
    description: '',
    imageUrl: '',
    timestamp: null,
    metadata: {}
  }),
  // Reset function
  (obj) => {
    obj.id = null;
    obj.title = '';
    obj.description = '';
    obj.imageUrl = '';
    obj.timestamp = null;
    obj.metadata = {};
  },
  100 // Max pool size
);

// Usage in component
const OptimizedList = ({ data }) => {
  const [items, setItems] = useState([]);
  
  useEffect(() => {
    // Process data with object pooling
    const processedItems = data.map(rawItem => {
      const item = ListItemPool.acquire();
      
      item.id = rawItem.id;
      item.title = rawItem.title;
      item.description = rawItem.description;
      item.imageUrl = rawItem.imageUrl;
      item.timestamp = new Date(rawItem.timestamp);
      item.metadata = { ...rawItem.metadata };
      
      return item;
    });
    
    setItems(processedItems);
    
    // Cleanup on unmount
    return () => {
      processedItems.forEach(item => {
        ListItemPool.release(item);
      });
    };
  }, [data]);
  
  return (
    <FlatList
      data={items}
      renderItem={({ item }) => <ListItem item={item} />}
      keyExtractor={item => item.id}
      removeClippedSubviews={true}
      maxToRenderPerBatch={10}
      windowSize={5}
      initialNumToRender={10}
    />
  );
};

Memory-Efficient Caching

kotlin
// Android - LRU Cache implementation
class MemoryEfficientCache<K, V> {
    private val cache: LruCache<K, V>
    private val maxMemory = Runtime.getRuntime().maxMemory()
    private val cacheSize = (maxMemory / 8).toInt() // 1/8 of available memory
    
    init {
        cache = object : LruCache<K, V>(cacheSize) {
            override fun sizeOf(key: K, value: V): Int {
                return when (value) {
                    is Bitmap -> value.byteCount
                    is String -> value.length * 2 // 2 bytes per char
                    is ByteArray -> value.size
                    else -> 1
                }
            }
            
            override fun entryRemoved(
                evicted: Boolean,
                key: K,
                oldValue: V,
                newValue: V?
            ) {
                // Cleanup removed entries
                if (oldValue is Bitmap && !oldValue.isRecycled) {
                    oldValue.recycle()
                }
            }
        }
    }
    
    fun put(key: K, value: V) {
        cache.put(key, value)
    }
    
    fun get(key: K): V? {
        return cache.get(key)
    }
    
    fun remove(key: K): V? {
        return cache.remove(key)
    }
    
    fun clear() {
        cache.evictAll()
    }
    
    fun getMemoryUsage(): CacheStats {
        return CacheStats(
            size = cache.size(),
            hitCount = cache.hitCount(),
            missCount = cache.missCount(),
            evictionCount = cache.evictionCount()
        )
    }
}

// Bitmap cache with memory pressure handling
class BitmapCache {
    private val memoryCache = MemoryEfficientCache<String, Bitmap>()
    private val diskCache = DiskLruCache.open(cacheDir, 1, 1, 50 * 1024 * 1024) // 50MB
    
    init {
        // Memory pressure listener
        registerComponentCallbacks(object : ComponentCallbacks2 {
            override fun onConfigurationChanged(newConfig: Configuration) {}
            
            override fun onLowMemory() {
                memoryCache.clear()
            }
            
            override fun onTrimMemory(level: Int) {
                when (level) {
                    ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
                    ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> {
                        memoryCache.clear()
                    }
                    ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN -> {
                        // Clear half of the cache
                        val currentSize = memoryCache.getMemoryUsage().size
                        for (i in 0 until currentSize / 2) {
                            // Remove oldest entries
                        }
                    }
                }
            }
        })
    }
    
    fun getBitmap(key: String): Bitmap? {
        // Try memory cache first
        memoryCache.get(key)?.let { return it }
        
        // Try disk cache
        return loadFromDiskCache(key)?.also { bitmap ->
            memoryCache.put(key, bitmap)
        }
    }
    
    fun putBitmap(key: String, bitmap: Bitmap) {
        memoryCache.put(key, bitmap)
        saveToDiskCache(key, bitmap)
    }
    
    private fun loadFromDiskCache(key: String): Bitmap? {
        return try {
            diskCache.get(key)?.getInputStream(0)?.use { inputStream ->
                BitmapFactory.decodeStream(inputStream)
            }
        } catch (e: IOException) {
            null
        }
    }
    
    private fun saveToDiskCache(key: String, bitmap: Bitmap) {
        try {
            diskCache.edit(key)?.let { editor ->
                editor.newOutputStream(0).use { outputStream ->
                    bitmap.compress(Bitmap.CompressFormat.PNG, 90, outputStream)
                }
                editor.commit()
            }
        } catch (e: IOException) {
            // Handle error
        }
    }
}

data class CacheStats(
    val size: Int,
    val hitCount: Long,
    val missCount: Long,
    val evictionCount: Long
) {
    val hitRate: Double get() = hitCount.toDouble() / (hitCount + missCount)
}

Lazy Loading ve Virtual Lists

Virtual List Implementation

dart
// Flutter - Virtual scrolling implementation
class VirtualListView extends StatefulWidget {
  final List<dynamic> items;
  final double itemHeight;
  final Widget Function(BuildContext, int, dynamic) itemBuilder;
  
  const VirtualListView({
    Key? key,
    required this.items,
    required this.itemHeight,
    required this.itemBuilder,
  }) : super(key: key);
  
  @override
  _VirtualListViewState createState() => _VirtualListViewState();
}

class _VirtualListViewState extends State<VirtualListView> {
  late ScrollController _scrollController;
  int _startIndex = 0;
  int _endIndex = 0;
  double _viewportHeight = 0;
  
  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController();
    _scrollController.addListener(_onScroll);
  }
  
  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }
  
  void _onScroll() {
    final scrollOffset = _scrollController.offset;
    final newStartIndex = (scrollOffset / widget.itemHeight).floor();
    final visibleItemCount = (_viewportHeight / widget.itemHeight).ceil() + 2; // Buffer
    final newEndIndex = (newStartIndex + visibleItemCount).clamp(0, widget.items.length);
    
    if (newStartIndex != _startIndex || newEndIndex != _endIndex) {
      setState(() {
        _startIndex = newStartIndex;
        _endIndex = newEndIndex;
      });
    }
  }
  
  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        _viewportHeight = constraints.maxHeight;
        _onScroll(); // Update indices
        
        final totalHeight = widget.items.length * widget.itemHeight;
        final topPadding = _startIndex * widget.itemHeight;
        final bottomPadding = totalHeight - (_endIndex * widget.itemHeight);
        
        return ListView.builder(
          controller: _scrollController,
          itemCount: _endIndex - _startIndex + 2, // +2 for padding items
          itemBuilder: (context, index) {
            if (index == 0) {
              return SizedBox(height: topPadding);
            } else if (index == _endIndex - _startIndex + 1) {
              return SizedBox(height: bottomPadding);
            } else {
              final actualIndex = _startIndex + index - 1;
              return SizedBox(
                height: widget.itemHeight,
                child: widget.itemBuilder(context, actualIndex, widget.items[actualIndex]),
              );
            }
          },
        );
      },
    );
  }
}

// Lazy loading data manager
class LazyDataManager<T> {
  final Future<List<T>> Function(int offset, int limit) _loadData;
  final List<T> _items = [];
  final Set<int> _loadingPages = {};
  final Map<int, List<T>> _pageCache = {};
  
  final int pageSize;
  bool _hasMore = true;
  
  LazyDataManager({
    required Future<List<T>> Function(int offset, int limit) loadData,
    this.pageSize = 20,
  }) : _loadData = loadData;
  
  List<T> get items => _items;
  bool get hasMore => _hasMore;
  
  Future<void> loadMore() async {
    if (!_hasMore || _loadingPages.isNotEmpty) return;
    
    final offset = _items.length;
    final pageIndex = offset ~/ pageSize;
    
    if (_pageCache.containsKey(pageIndex)) {
      _items.addAll(_pageCache[pageIndex]!);
      return;
    }
    
    _loadingPages.add(pageIndex);
    
    try {
      final newItems = await _loadData(offset, pageSize);
      
      if (newItems.length < pageSize) {
        _hasMore = false;
      }
      
      _pageCache[pageIndex] = newItems;
      _items.addAll(newItems);
      
      // Memory management: remove old pages
      if (_pageCache.length > 10) {
        final oldestPage = _pageCache.keys.first;
        _pageCache.remove(oldestPage);
      }
    } catch (error) {
      // Handle error
      print('Data loading error: $error');
    } finally {
      _loadingPages.remove(pageIndex);
    }
  }
  
  void reset() {
    _items.clear();
    _pageCache.clear();
    _loadingPages.clear();
    _hasMore = true;
  }
  
  T? getItem(int index) {
    if (index < _items.length) {
      return _items[index];
    }
    
    // Trigger lazy loading if near the end
    if (index >= _items.length - 5 && _hasMore) {
      loadMore();
    }
    
    return null;
  }
}

Memory Profiling ve Debugging

Memory Leak Detection

swift
// iOS - Memory leak detection tools
class MemoryLeakDetector {
    private static var instances: [String: WeakObjectSet] = [:]
    
    static func track<T: AnyObject>(_ object: T, name: String? = nil) {
        let className = String(describing: type(of: object))
        let trackingName = name ?? className
        
        if instances[trackingName] == nil {
            instances[trackingName] = WeakObjectSet()
        }
        
        instances[trackingName]?.add(object)
    }
    
    static func printMemoryReport() {
        print("=== Memory Report ===")
        
        for (name, objectSet) in instances {
            let count = objectSet.count
            print("\(name): \(count) instances")
            
            if count > 100 {
                print("⚠️ Potential memory leak detected for \(name)")
            }
        }
        
        print("===================")
    }
    
    static func detectLeaks() -> [String] {
        var leaks: [String] = []
        
        for (name, objectSet) in instances {
            let count = objectSet.count
            
            // Heuristic: more than 100 instances might indicate a leak
            if count > 100 {
                leaks.append("\(name): \(count) instances")
            }
        }
        
        return leaks
    }
}

class WeakObjectSet {
    private var objects: [WeakBox] = []
    
    func add<T: AnyObject>(_ object: T) {
        // Clean up nil references first
        objects = objects.filter { $0.object != nil }
        
        objects.append(WeakBox(object))
    }
    
    var count: Int {
        // Clean up and return count
        objects = objects.filter { $0.object != nil }
        return objects.count
    }
}

private class WeakBox {
    weak var object: AnyObject?
    
    init(_ object: AnyObject) {
        self.object = object
    }
}

// Usage in ViewController
class MonitoredViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Track this instance
        MemoryLeakDetector.track(self)
        
        // Set up memory monitoring
        setupMemoryMonitoring()
    }
    
    private func setupMemoryMonitoring() {
        #if DEBUG
        Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { _ in
            MemoryLeakDetector.printMemoryReport()
        }
        #endif
    }
}

// Memory usage monitoring
class MemoryMonitor {
    static func getCurrentMemoryUsage() -> MemoryUsage {
        var info = mach_task_basic_info()
        var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size)/4
        
        let kerr = withUnsafeMutablePointer(to: &info) {
            $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
                task_info(mach_task_self_,
                         task_flavor_t(MACH_TASK_BASIC_INFO),
                         $0,
                         &count)
            }
        }
        
        if kerr == KERN_SUCCESS {
            let usedMemory = Double(info.resident_size)
            let totalMemory = Double(ProcessInfo.processInfo.physicalMemory)
            
            return MemoryUsage(
                used: usedMemory,
                total: totalMemory,
                percentUsed: (usedMemory / totalMemory) * 100
            )
        }
        
        return MemoryUsage(used: 0, total: 0, percentUsed: 0)
    }
    
    static func logMemoryUsage() {
        let usage = getCurrentMemoryUsage()
        let usedMB = usage.used / (1024 * 1024)
        let totalMB = usage.total / (1024 * 1024)
        
        print("Memory Usage: \(String(format: "%.1f", usedMB))MB / \(String(format: "%.0f", totalMB))MB (\(String(format: "%.1f", usage.percentUsed))%)")
        
        if usage.percentUsed > 80 {
            print("⚠️ High memory usage detected!")
        }
    }
}

struct MemoryUsage {
    let used: Double
    let total: Double
    let percentUsed: Double
}

Automated Memory Testing

kotlin
// Android - Automated memory testing
class MemoryTestSuite {
    
    @Test
    fun testMemoryLeakAfterActivityDestroy() {
        val activityRule = ActivityTestRule(MainActivity::class.java)
        val initialMemory = getMemoryUsage()
        
        // Create and destroy activity multiple times
        repeat(10) {
            val activity = activityRule.launchActivity(Intent())
            // Perform UI operations
            performUIOperations(activity)
            
            // Destroy activity
            activity.finish()
            waitForGC()
        }
        
        val finalMemory = getMemoryUsage()
        val memoryGrowth = finalMemory - initialMemory
        
        // Assert memory growth is within acceptable limits
        assert(memoryGrowth < ACCEPTABLE_MEMORY_GROWTH) {
            "Memory leak detected: grew by ${memoryGrowth}MB"
        }
    }
    
    @Test
    fun testRecyclerViewMemoryUsage() {
        val recyclerView = RecyclerView(context)
        val adapter = TestAdapter()
        
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(context)
        
        val initialMemory = getMemoryUsage()
        
        // Simulate scrolling with large dataset
        val largeDataset = generateLargeDataset(10000)
        adapter.updateData(largeDataset)
        
        // Simulate rapid scrolling
        repeat(100) {
            recyclerView.scrollBy(0, 100)
            Thread.sleep(10)
        }
        
        val peakMemory = getMemoryUsage()
        
        // Clear data and force GC
        adapter.updateData(emptyList())
        waitForGC()
        
        val finalMemory = getMemoryUsage()
        
        // Assert memory is properly released
        val retainedMemory = finalMemory - initialMemory
        assert(retainedMemory < MAX_RETAINED_MEMORY) {
            "RecyclerView retaining too much memory: ${retainedMemory}MB"
        }
    }
    
    private fun getMemoryUsage(): Long {
        val runtime = Runtime.getRuntime()
        return (runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024)
    }
    
    private fun waitForGC() {
        repeat(3) {
            System.gc()
            System.runFinalization()
            Thread.sleep(100)
        }
    }
    
    private fun performUIOperations(activity: Activity) {
        // Simulate user interactions
        activity.runOnUiThread {
            // Create views, load images, etc.
            repeat(50) {
                val imageView = ImageView(activity)
                val bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
                imageView.setImageBitmap(bitmap)
                
                // Add to layout
                (activity.findViewById<ViewGroup>(android.R.id.content)).addView(imageView)
                
                // Remove immediately
                (activity.findViewById<ViewGroup>(android.R.id.content)).removeView(imageView)
                
                // Cleanup
                bitmap.recycle()
            }
        }
    }
    
    companion object {
        private const val ACCEPTABLE_MEMORY_GROWTH = 50L // MB
        private const val MAX_RETAINED_MEMORY = 10L // MB
    }
}

// Memory allocation tracker
class AllocationTracker {
    private val allocations = mutableMapOf<String, AllocationStats>()
    
    fun trackAllocation(objectType: String, size: Long) {
        val stats = allocations.getOrPut(objectType) {
            AllocationStats(objectType)
        }
        
        stats.totalAllocations++
        stats.totalSize += size
        stats.currentSize += size
    }
    
    fun trackDeallocation(objectType: String, size: Long) {
        allocations[objectType]?.let { stats ->
            stats.totalDeallocations++
            stats.currentSize -= size
        }
    }
    
    fun getReport(): String {
        val report = StringBuilder()
        report.appendLine("=== Allocation Report ===")
        
        for (stats in allocations.values.sortedByDescending { it.currentSize }) {
            report.appendLine(
                "${stats.objectType}: " +
                "Current: ${stats.currentSize / 1024}KB, " +
                "Allocated: ${stats.totalAllocations}, " +
                "Deallocated: ${stats.totalDeallocations}, " +
                "Leaked: ${stats.totalAllocations - stats.totalDeallocations}"
            )
        }
        
        return report.toString()
    }
}

data class AllocationStats(
    val objectType: String,
    var totalAllocations: Long = 0,
    var totalDeallocations: Long = 0,
    var totalSize: Long = 0,
    var currentSize: Long = 0
)

Bu bellek etkin UI yönetimi dokümantasyonu, mobil uygulamalarda memory leak'leri önleme, etkin caching stratejileri, object pooling, lazy loading ve memory profiling konularında kapsamlı rehberlik sağlamaktadır. Platform-specific implementasyonlar ve best practice'ler ile bellek optimizasyonu konusunda derinlemesine bilgi sunmaktadır.

Eren Demir tarafından oluşturulmuştur.