पठनीयता के लिए, मैंने कोड उदाहरण पोस्ट किए हैं जो मेरे समाधान पहले संदर्भित करते हैं, और फिर मैंने संख्यात्मक सूची में अपने समाधान की व्याख्या सूचीबद्ध की।एंड्रॉइड: बिटमैप्स, मेमोरी उपयोग और स्केलिंग के बारे में प्रश्न
मैं थोड़ी देर के लिए इसके साथ संघर्ष कर रहा हूं। मैंने बहुत पढ़ा है, यहां प्रश्न पूछे हैं, और प्रयोग किया है; लेकिन एक सभ्य समाधान के साथ नहीं आया है। मुझे इनपुट धाराओं से विभिन्न आकार की छवियों को पढ़ने की ज़रूरत है, और उन्हें अपनी गुणवत्ता की बाधाओं के रूप में उच्च गुणवत्ता के साथ प्रदर्शित करने की आवश्यकता है। नीचे दिए गए विकल्प हैं, जिनमें से कोई भी मेरे लिए बहुत अच्छा प्रतीत नहीं होता है। किसी भी मदद या इनपुट की सराहना की जाएगी।
public class NativeTest extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
double nativeUsage = Debug.getNativeHeapAllocatedSize();
Log.i("memory", nativeUsage+"");
}
}
double getAvailableMemory()
{
//current heap size
double heapSize = Runtime.getRuntime().totalMemory();
//amount available in heap
double heapRemaining = Runtime.getRuntime().freeMemory();
double nativeUsage = Debug.getNativeHeapAllocatedSize();
double memoryAvailable = Runtime.getRuntime().maxMemory() - (heapSize - heapRemaining) - nativeUsage;
return memoryAvailable;
}
Bitmap createImageTrialAndError(InputStream stream)
{
Bitmap image = null;
int dowsample = 1;
while(image == null)
{
try
{
Options opts = new Options();
opts.inSampleSize = downsample;
image = BitmapFactory.decodeStream(imgStream, null, opts);
}
catch (OutOfMemoryError ome)
{
downsample = downsample * 2;
Log.i("out of mem", "try using: " + downsample);
}
}
return image;
}
- आदर्श समाधान यदि बिटमैप एक Bitmap.drawBitmap (InputStream ...) विधि पड़ा होगा। यह मुझे बिटमैप के लिए स्मृति आवंटित किए बिना इनपुटस्ट्रीम से आकर्षित करने की अनुमति देगा। हां, यह एक विकल्प नहीं है।
- उपलब्ध स्मृति के अनुसार बिटमैप स्केल करें। इसमें बिटमैप की चौड़ाई और ऊंचाई को पुनर्प्राप्त करना शामिल है, बाइटमैप की संख्या की गणना करने के लिए बिटमैप को
width * height * 4
के रूप में आवश्यक स्मृति की गणना करना आवश्यक है, और फिरBitmapFactory.Options.inSampleSize
जैसे कि बिटमैप उपलब्ध होने की तुलना में कम स्मृति का उपयोग करेगा। हालांकि, यह विकल्प विफल रहता है क्योंकि मैं उपलब्ध स्मृति की गणना करने के लिए एक दूरस्थ रूप से विश्वसनीय तरीका नहीं ढूंढ पाया है। नीचे उपलब्ध GetMemory() विधि ऐसा लगता है जैसे इसे काम करना चाहिए: यह उपलब्ध स्मृति को अधिकतम मेमोरी के रूप में गणना करता है - जावा ढेर में उपयोग की जाने वाली मेमोरी - देशी ढेर में उपयोग की जाने वाली मेमोरी।
दुर्भाग्य से, यह सूत्र बहुत अविश्वसनीय परिणाम देता है। मुख्य रूप से क्योंकिDebug.getNativeHeapAllocatedSize()
बिटमैप मेमोरी उपयोग का सटीक प्रतिनिधित्व प्रतीत नहीं होता है। इसकी गलतता का एक स्पष्ट उदाहरण नीचे मूलभूत गतिविधि है। मेरे सैमसंग गैलेक्सी टैबलेट पर, लॉग स्टेटमेंट आउटपुट किया गया है: 3759416.0। एक खाली गतिविधि के लिए मूल आवंटन के 3.75 एमबी, स्पष्ट रूप से बिटमैप स्केलिंग निर्धारित करने के लिए एक विश्वसनीय तरीका नहीं है। - एक के स्केलिंग कारक से शुरू करें, और बिटमैप को प्रारंभ करने का प्रयास करें; यदि स्मृति के कारण प्रारंभिक विफल रहता है, तो स्केलिंग कारक को दोगुना करें और पुनः प्रयास करें; और सफल होने तक इस प्रक्रिया को दोहराएं। यह
createBitmapTrialAndError()
द्वारा सचित्र है। यह वास्तव में आश्चर्यजनक रूप से प्रभावी है और बहुत धीमी नहीं है। हालांकि, यह बहुत अवांछनीय है क्योंकि मैं अपने आवेदन में कहीं और सॉफ़्ट रेफरेंस का उपयोग करता हूं, और मेमोरी से बाहर निकलने से इन सॉफ़्ट रेफरेंस का संग्रह होता है, जिसका महत्वपूर्ण प्रदर्शन प्रभाव पड़ता है। शुरुआत में उचित स्केलिंग कारक को जानना अधिक वांछनीय होगा, जो इन सॉफ्ट रेफरेंस के अनावश्यक संग्रह से बच जाएगा। - मेरा अंतिम समाधान थोड़ा संदिग्ध लगता है। असल में यह 2 & 3 को जोड़ती है, लेकिन
Debug.getNativeAllocatedSize()
का उपयोग नहीं करती है। इसके बजाए, मैं अपने खुद के बिटमैप मेमोरी आवंटन को ट्रैक करता हूं, जहां भी मैं बिटमैप्स आवंटित करता हूं और उनकी मेमोरी उपयोग को टैल करता हूं, और फिर रीसायकल के किसी भी बिटमैप्स के मेमोरी उपयोग को घटाता हूं। बिटमैप्स के लिए उचित स्केलिंग कारक की गणना करने के लिए, मैं getAvailableMemory() में देशी उपयोग के स्थान पर इस मान का उपयोग करता हूं। और यदि इस विधि का उपयोग करने में आउट ऑफ़ मेमोरी अपवाद होता है, तो मैं स्वीकार्य पैमाने की गणना करने के लिए समाधान 3 को फ़ॉलबैक तरीके के रूप में उपयोग करता हूं। इसके साथ स्पष्ट समस्या मेरे अपने मूल स्मृति उपयोग को ट्रैक करने की कोशिश करने की विशाल स्केचनेस है, लेकिन मेरे लिए, यह सबसे अच्छा समाधान प्रतीत होता है।
विकल्प 4 क्या आप के साथ फंस रहे हो रहा है। मैंने एक बार में कुछ सौ बिटमैप्स लोड करने की कोशिश करने के साथ कुछ काम किया है और उन्हें गतिशील रूप से स्केल किया है कि वे वास्तव में स्क्रीन पर कितने बड़े होंगे। आपके मामले में, अपना सर्वश्रेष्ठ अनुमान + मेमोरी ट्रैकिंग का उपयोग करना एक अच्छा तरीका है। नोट: विकल्प 1 को अभी भी ऑब्जेक्ट के लिए स्मृति आवंटित करने की आवश्यकता होगी, इसलिए उस फ़ंक्शन के बारे में चिंता न करें जो मौजूदा नहीं है। – Haphazard
आपका बिटमैप स्क्रीन आकार से बड़ा नहीं हो सकता है ताकि नमूना आकार में शुरू करने के लिए एक अच्छी जगह हो, आप पूर्ण बिटमैप आयामों को स्मृति में पढ़ने के बिना डीकोडइनबाउंड का उपयोग कर सकते हैं और फिर आप इसे नीचे नमूना में पढ़ सकते हैं। 3.0+ पर भी बिटमैप जावा ढेर पर संग्रहीत हैं और मूल स्मृति नहीं है। – smith324
सभी को यह बताना है कि "getAvailableMemory()" नकारात्मक संख्याएं वापस कर सकता है। – Zammbi