Fresco加载本地图片内存占用过高问题排查求助
Hey there! It makes total sense you're confused—using Fresco just to display local images shouldn't bloat your memory more than your old setup. Let's break down why this might be happening and fix it step by step.
Why Fresco's Using More Memory Out of the Box
Fresco's default initialization (Fresco.initialize(context)) sets up a memory cache tuned for full-featured use (including network downloads, large image sets, etc.). Even if you're not using the network part, the default cache size and overhead from unused features can add up. Plus, looking at your code, there are a few inefficiencies contributing to the problem.
Fixes to Reduce Memory Usage
1. Customize Fresco Initialization to Trim Unused Features & Shrink Cache
Since you only use Fresco for local files, you can disable network components and shrink the memory cache to match your actual needs. Here's how to set this up:
// In your Application class or initialization entry point ImagePipelineConfig config = ImagePipelineConfig.newBuilder(context) // Disable network fetching entirely—we don't need it .setNetworkFetcher(new VoidNetworkFetcher()) // Customize memory cache parameters to fit your app's constraints .setBitmapMemoryCacheParamsSupplier(new Supplier<MemoryCacheParams>() { @Override public MemoryCacheParams get() { // Adjust these values based on your app's memory limits final int maxCacheSize = (int) (Runtime.getRuntime().maxMemory() / 8); // 1/8 of total app memory final int maxCacheSizeOnLowMemory = (int) (Runtime.getRuntime().maxMemory() / 16); // Smaller for low-memory situations final int maxCacheEntries = 200; // Limit number of cached bitmaps return new MemoryCacheParams( maxCacheSize, maxCacheEntries, maxCacheSizeOnLowMemory, maxCacheEntries / 2, Integer.MAX_VALUE ); } }) // Disable disk cache since we're loading local files directly .setMainDiskCacheConfig(DiskCacheConfig.newBuilder(context) .setEnabled(false) .build()) .build(); Fresco.initialize(context, config);
2. Reuse GenericDraweeHierarchy Instead of Creating New Ones
In your current code, you build a new GenericDraweeHierarchy every time setImage runs. This creates unnecessary object overhead and increases garbage collection pressure. Instead, reuse hierarchies based on their configuration (rounded corners, fade duration):
// Cache hierarchies to avoid redundant creation private static final HashMap<String, GenericDraweeHierarchy> HIERARCHY_CACHE = new HashMap<>(); private GenericDraweeHierarchy getOrCreateHierarchy(Context context, boolean fadeIn, boolean isRound) { // Create a unique key for this hierarchy's configuration String key = fadeIn + "_" + isRound; if (HIERARCHY_CACHE.containsKey(key)) { return HIERARCHY_CACHE.get(key); } GenericDraweeHierarchyBuilder builder = GenericDraweeHierarchyBuilder.newInstance(context.getResources()); if (fadeIn) { builder.setFadeDuration(FADE_IN_TIME); } if (isRound) { builder.setRoundingParams(RoundingParams.asCircle()); } GenericDraweeHierarchy hierarchy = builder.build(); HIERARCHY_CACHE.put(key, hierarchy); return hierarchy; } // Updated setImage method using cached hierarchies private void setImage(Context context, boolean isSvg, final SimpleDraweeView imageView, final String filePath, ImageData data) { GenericDraweeHierarchy hierarchy = getOrCreateHierarchy(context, data.isFadeInBitmap(), data.isRound()); int width = imageView.getLayoutParams().width; int height = imageView.getLayoutParams().height; ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(UriUtil.getUriForFile(new File(filePath))); if (width > 0 && height > 0) { imageRequestBuilder.setResizeOptions(new ResizeOptions(width, height)) // Enable downsampling to load a memory-efficient bitmap matching the ImageView size .setDownsampleEnabled(true); } DraweeController controller = Fresco.newDraweeControllerBuilder() .setOldController(imageView.getController()) .setImageRequest(imageRequestBuilder.build()) .build(); imageView.setHierarchy(hierarchy); imageView.setController(controller); if(isSvg) { imageView.setLayerType(View.LAYER_TYPE_SOFTWARE,null); } }
3. Clean Up Resources Properly
Make sure you release Fresco resources when views are no longer needed (e.g., in fragment onDestroyView or activity onDestroy):
// In your fragment or activity @Override public void onDestroyView() { super.onDestroyView(); if (imageView != null) { imageView.setController(null); } }
Why These Changes Work
- Disabling network and disk cache removes unused components that waste memory.
- Shrinking the memory cache ensures Fresco doesn't hoard more memory than necessary for your local image use case.
- Reusing hierarchies cuts down on object creation and reduces garbage collection overhead.
- Downsampling makes Fresco load a smaller, more efficient bitmap that fits your
ImageView's exact size.
Give these tweaks a try, and you should see Fresco's memory usage drop to match (or even beat) your previous caching mechanism!
内容的提问来源于stack exchange,提问作者Piyush

