Sie können die Größe des Heapspeichers nicht dynamisch erhöhen, aber Sie können die Verwendung von Heap mithilfe von anfordern.
android: largeHeap = "wahr"
In manifest.xml
können Sie in Ihrem Manifest diese Zeilen hinzufügen, die in bestimmten Situationen funktionieren.
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
Gibt an, ob die Prozesse Ihrer Anwendung mit einem großen Dalvik-Heap erstellt werden sollen. Dies gilt für alle für die Anwendung erstellten Prozesse. Dies gilt nur für die erste in einen Prozess geladene Anwendung. Wenn Sie eine gemeinsam genutzte Benutzer-ID verwenden, um mehreren Anwendungen die Verwendung eines Prozesses zu ermöglichen, müssen alle diese Option konsistent verwenden, da sonst unvorhersehbare Ergebnisse erzielt werden. Die meisten Apps sollten dies nicht benötigen und sich stattdessen darauf konzentrieren, die Gesamtspeicherauslastung zu reduzieren, um die Leistung zu verbessern. Das Aktivieren dieser Option garantiert auch keine feste Erhöhung des verfügbaren Speichers, da einige Geräte durch ihren insgesamt verfügbaren Speicher eingeschränkt sind.
Verwenden Sie die Methoden getMemoryClass()
oder , um die verfügbare Speichergröße zur Laufzeit abzufragen getLargeMemoryClass()
.
Wenn immer noch Probleme auftreten, sollte dies auch funktionieren
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
mBitmapInsurance = BitmapFactory.decodeFile(mCurrentPhotoPath,options);
Wenn ein Wert> 1 festgelegt ist, wird der Decoder aufgefordert, das Originalbild zu unterabtasten und ein kleineres Bild zurückzugeben, um Speicherplatz zu sparen.
Dies ist die optimale Verwendung von BitmapFactory.Options.inSampleSize im Hinblick auf die Geschwindigkeit der Bildanzeige. In der Dokumentation wird die Verwendung von Werten mit einer Potenz von 2 erwähnt, daher arbeite ich mit 2, 4, 8, 16 usw.
Gehen wir näher auf die Bildabtastung ein:
Zum Beispiel lohnt es sich nicht, ein Bild mit 1024 x 768 Pixeln in den Speicher zu laden, wenn es irgendwann in einem Miniaturbild mit 128 x 128 Pixeln in einem Bild angezeigt wird ImageView
.
Um den Decoder zu sagen , das Bild unterabzutasten, eine kleinere Version in dem Speicher, Satz Laden inSampleSize
zu true
in Ihrem BitmapFactory.Options
Objekt. Beispielsweise erzeugt ein Bild mit einer Auflösung von 2100 x 1500 Pixel, das mit einer Auflösung inSampleSize
von 4 dekodiert wird, eine Bitmap von ungefähr 512 x 384. Das Laden in den Speicher verwendet 0,75 MB anstelle von 12 MB für das vollständige Image (unter der Annahme einer Bitmap-Konfiguration von ARGB_8888
). Hier ist eine Methode zum Berechnen eines Stichprobengrößenwerts, der eine Zweierpotenz basierend auf einer Zielbreite und -höhe ist:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
Hinweis : Eine Zweierpotenz wird berechnet, da der Decoder einen Endwert verwendet, indem er gemäß der inSampleSize
Dokumentation auf die nächste Zweierpotenz abrundet
.
Um diese Methode zu verwenden, dekodieren Sie zuerst mit inJustDecodeBounds
set to true
, übergeben Sie die Optionen und dekodieren Sie dann erneut mit dem neuen inSampleSize
Wert und inJustDecodeBounds
setzen Sie auf false
:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
Diese Methode erleichtert das Laden einer Bitmap beliebig großer Größe in eine Bitmap mit ImageView
einer Miniaturansicht von 100 x 100 Pixel, wie im folgenden Beispielcode gezeigt:
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
Sie können einen ähnlichen Prozess ausführen, um Bitmaps aus anderen Quellen zu dekodieren, indem Sie die entsprechende BitmapFactory.decode*
Methode nach Bedarf ersetzen .
Ich fand diesen Code auch interessant:
private Bitmap getBitmap(String path) {
Uri uri = getImageUri(path);
InputStream in = null;
try {
final int IMAGE_MAX_SIZE = 1200000;
in = mContentResolver.openInputStream(uri);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, o);
in.close();
int scale = 1;
while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) >
IMAGE_MAX_SIZE) {
scale++;
}
Log.d(TAG, "scale = " + scale + ", orig-width: " + o.outWidth + ",
orig-height: " + o.outHeight);
Bitmap bitmap = null;
in = mContentResolver.openInputStream(uri);
if (scale > 1) {
scale--;
o = new BitmapFactory.Options();
o.inSampleSize = scale;
bitmap = BitmapFactory.decodeStream(in, null, o);
int height = bitmap.getHeight();
int width = bitmap.getWidth();
Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
height: " + height);
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, (int) x,
(int) y, true);
bitmap.recycle();
bitmap = scaledBitmap;
System.gc();
} else {
bitmap = BitmapFactory.decodeStream(in);
}
in.close();
Log.d(TAG, "bitmap size - width: " +bitmap.getWidth() + ", height: " +
bitmap.getHeight());
return bitmap;
} catch (IOException e) {
Log.e(TAG, e.getMessage(),e);
return null;
}
So verwalten Sie den Speicher Ihrer App: Link
Es ist keine gute Idee, android:largeHeap="true"
hier den Auszug aus Google zu verwenden, der dies erklärt:
Die Möglichkeit, einen großen Heap anzufordern, ist jedoch nur für eine kleine Anzahl von Apps vorgesehen, die die Notwendigkeit rechtfertigen, mehr RAM zu verbrauchen (z. B. eine große Fotobearbeitungs-App). Fordern Sie niemals einen großen Heap an, nur weil Ihnen der Speicher ausgeht und Sie eine schnelle Lösung benötigen. Sie sollten ihn nur verwenden, wenn Sie genau wissen, wo Ihr gesamter Speicher zugewiesen wird und warum er beibehalten werden muss. Selbst wenn Sie sicher sind, dass Ihre App den großen Haufen rechtfertigen kann, sollten Sie es vermeiden, ihn so weit wie möglich anzufordern. Die Verwendung des zusätzlichen Speichers wird sich zunehmend nachteilig auf die allgemeine Benutzererfahrung auswirken, da die Speicherbereinigung länger dauert und die Systemleistung langsamer sein kann, wenn Aufgaben gewechselt oder andere allgemeine Vorgänge ausgeführt werden.
Nachdem ich exkret gearbeitet habe, out of memory errors
würde ich sagen, dass es keine Sünde ist, dies dem Manifest hinzuzufügen, um das Problem zu vermeiden
Überprüfen des App-Verhaltens auf der Android Runtime (ART)
Die Android-Laufzeit (ART) ist die Standardlaufzeit für Geräte mit Android 5.0 (API-Stufe 21) und höher. Diese Laufzeit bietet eine Reihe von Funktionen, die die Leistung und Glätte der Android-Plattform und -Apps verbessern. Weitere Informationen zu den neuen Funktionen von ART finden Sie unter Einführung in ART .
Einige Techniken, die auf Dalvik funktionieren, funktionieren jedoch nicht auf ART. In diesem Dokument erfahren Sie, worauf Sie bei der Migration einer vorhandenen App achten müssen, um mit ART kompatibel zu sein. Die meisten Apps sollten nur funktionieren, wenn sie mit ART ausgeführt werden.
Beheben von Problemen mit der Garbage Collection (GC)
Unter Dalvik finden es Apps häufig nützlich, System.gc () explizit aufzurufen, um die Garbage Collection (GC) aufzufordern. Dies sollte bei ART weitaus weniger erforderlich sein, insbesondere wenn Sie die Garbage Collection aufrufen, um Vorkommen vom Typ GC_FOR_ALLOC zu verhindern oder die Fragmentierung zu verringern. Sie können überprüfen, welche Laufzeit verwendet wird, indem Sie System.getProperty ("java.vm.version") aufrufen. Wenn ART verwendet wird, beträgt der Wert der Eigenschaft "2.0.0" oder höher.
Darüber hinaus wird im Android Open-Source Project (AOSP) ein komprimierender Garbage Collector entwickelt, um die Speicherverwaltung zu verbessern. Aus diesem Grund sollten Sie die Verwendung von Techniken vermeiden, die mit der Komprimierung von GC nicht kompatibel sind (z. B. das Speichern von Zeigern auf Objektinstanzdaten). Dies ist besonders wichtig für Apps, die das Java Native Interface (JNI) verwenden. Weitere Informationen finden Sie unter Verhindern von JNI-Problemen.
Verhindern von JNI-Problemen
Das JNI von ART ist etwas strenger als das von Dalvik. Es ist eine besonders gute Idee, den CheckJNI-Modus zu verwenden, um häufige Probleme zu erkennen. Wenn Ihre App C / C ++ - Code verwendet, sollten Sie den folgenden Artikel lesen:
Sie können auch nativen Speicher ( NDK & JNI ) verwenden, sodass Sie die Beschränkung der Heap-Größe tatsächlich umgehen.
Hier sind einige Beiträge dazu:
und hier ist eine Bibliothek dafür gemacht: