2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Unter Memory Thrashing versteht man die Erstellung und Zerstörung einer großen Anzahl von Objekten in kurzer Zeit, was zu häufigen Garbage Collection-Aktivitäten (Garbage Collection, GC) führt. Diese häufige GC-Aktivität beansprucht viele CPU-Ressourcen und kann zu Anwendungsverzögerungen oder Leistungseinbußen führen.
Leistung: Die Speicherkurve ist gezackt.
Ein Speicherverlust tritt auf, wenn eine Anwendung Verweise auf Objekte enthält, die nicht mehr benötigt werden, was dazu führt, dass diese Objekte vom Garbage Collector nicht recycelt werden und somit Speicherplatz belegen, der hätte freigegeben werden können. Im Laufe der Zeit führen Speicherlecks dazu, dass immer weniger Speicher verfügbar ist, was schließlich zu Anwendungsabstürzen oder Leistungseinbußen führen kann.
Ein Speicherüberlauf tritt auf, wenn eine Anwendung versucht, mehr Speicherplatz zuzuweisen, das System die Anforderung jedoch nicht erfüllen kann, weil nicht mehr genügend Speicherplatz zum Zuweisen vorhanden ist. Dies führt normalerweise dazu, dass die Anwendung eine OutOfMemoryError-Ausnahme auslöst.
Java-Speicherstruktur: Heap, Stapel der virtuellen Maschine, Methodenbereich, Programmzähler, lokaler Methodenstapel.
Java-Speicherrecycling-Algorithmus:
Nachteile des Mark-Clear-Algorithmus: Markieren und Löschen sind nicht effizient und erzeugen eine große Anzahl diskontinuierlicher Speicherfragmente.
Replikationsalgorithmus: einfach zu implementieren und effizient auszuführen. Nachteile: Die Hälfte des Platzes wird verschwendet.
Mark-Compact-Algorithmus: Vermeiden Sie eine durch Mark-Clean verursachte Speicherfragmentierung und vermeiden Sie die Verschwendung von Speicherplatz beim Kopieralgorithmus.
Die elastische Zuordnung des Android-Speichers, der Zuordnungswert und der Maximalwert werden von bestimmten Geräten beeinflusst.
Der Dalvik-Recycling-Algorithmus und der ART-Recycling-Algorithmus sind beide Garbage-Collection-Mechanismen, die für die Speicherverwaltung im Android-Betriebssystem verwendet werden.
Dalvik-Recycling-Algorithmus:
Kunstrecycling-Algorithmus:
LMK-Mechanismus:
public class ShakeActivity extends AppCompatActivity {
private static Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
String str = "";
for (int i = 0; i < 10000000; i++) {
str += i;
}
mHandler.sendEmptyMessageDelayed(1, 30);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shake);
}
public void startClick(View view) {
mHandler.sendEmptyMessage(1);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
}
Memory Profiler kann Speicherzuordnungen anzeigen. Klicken Sie auf „Java/Kotlin-Zuordnungen aufzeichnen“.
Bedeutung des oben Gesagten:
Folgende Bedeutungen:
malloc()
odernew
Die Anzahl der vom Operator zugewiesenen Objekte.free()
oderdelete
Die Anzahl der vom Operator freigegebenen Objekte.Analyse des obigen Bildes:
Die Werte für Zuweisungen und Freigaben in diesem Bereich sind relativ ähnlich und die flache Größe ist relativ groß, was darauf hinweist, dass Objekte häufig erstellt und zerstört werden können.
Nach dem Klicken können Sie die Aufrufstapelinformationen anzeigen und in Kombination mit dem Code daraus schließen, dass im Handler ein Speicherjitterproblem vorliegt.
public class CallbackManager {
public static ArrayList<Callback> sCallbacks = new ArrayList<>();
public static void addCallback(Callback callback) {
sCallbacks.add(callback);
}
public static void removeCallback(Callback callback) {
sCallbacks.remove(callback);
}
}
public class LeakActivity extends AppCompatActivity implements Callback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leak);
ImageView imageView = findViewById(R.id.imageView);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.splash);
imageView.setImageBitmap(bitmap);
CallbackManager.addCallback(this);
}
@Override
public void onOperate() {
}
}
Abhängige Bibliotheken hinzufügen:
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
Nachdem ein Speicherverlust aufgetreten ist, generiert LeakCanary relevante Informationen und gibt sie automatisch aus:
Aus der obigen Abbildung ist ersichtlich, dass bei LeakActivity ein Speicherverlust vorliegt und die Referenzkettenbeziehung angezeigt wird.
Natürlich können Sie auch eine hprof-Datei generieren und spezifische Informationen über das Profiler-Tool anzeigen:
Wie aus dem obigen Bild hervorgeht, sind 10 Leckpunkte aufgetreten, einschließlich LeakActivity. Klicken Sie auf LeakActivity, um das Speicherleckobjekt anzuzeigen und die Referenzkette zu überprüfen.
Wenn Sie die Bildressourcen nach der Verwendung von Bitmap nicht freigeben, kann dies leicht passierenSpeicherverlust, der zu einem Speicherüberlauf führt。
Speicherrecycling:
Bitmap.recycle()
Führen Sie ein Bitmap-Recycling durch.Bitmap-Pixelkonfiguration:
Konfiguration | Belegte Bytegröße (Byte) | veranschaulichen |
---|---|---|
ALPHA_8 | 1 | einzelner transparenter Kanal |
RGB_565 | 2 | Einfache RGB-Tönung |
ARGB_8888 | 4 | 24-Bit-Echtfarbe |
RGBA_F16 | 8 | Android 8.0 Neu (HDR) |
Berechnen Sie den von Btimap belegten Speicher:
Problem mit der Ressourcendatei:
Testcode:
private void printBitmap(Bitmap bitmap, String drawable) {
String builder = drawable +
" Bitmap占用内存:" +
bitmap.getByteCount() +
" width:" +
bitmap.getWidth() +
" height:" +
bitmap.getHeight() +
" 1像素占用大小:" +
getByteBy1px(bitmap.getConfig());
Log.e("TAG", builder);
}
private int getByteBy1px(Bitmap.Config config) {
if (Bitmap.Config.ALPHA_8.equals(config)) {
return 1;
} else if (Bitmap.Config.RGB_565.equals(config)) {
return 2;
} else if (Bitmap.Config.ARGB_8888.equals(config)) {
return 4;
}
return 1;
}
// 逻辑密度
float density = metrics.density;
// 物理密度
int densityDpi = metrics.densityDpi;
Log.e("TAG", density + "-" + densityDpi);
// 1倍图
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.splash1);
printBitmap(bitmap1, "drawable-mdpi");
// 2倍图
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.splash2);
printBitmap(bitmap2, "drawable-xhdpi");
// 3倍图
Bitmap bitmap3 = BitmapFactory.decodeResource(getResources(), R.drawable.splash3);
printBitmap(bitmap3, "drawable-xxhdpi");
// 4倍图
Bitmap bitmap4 = BitmapFactory.decodeResource(getResources(), R.drawable.splash4);
printBitmap(bitmap4, "drawable-xxxhdpi");
// drawable
Bitmap bitmap5 = BitmapFactory.decodeResource(getResources(), R.drawable.splash);
printBitmap(bitmap5, "drawable");
/*
3.0-480
drawable-mdpi Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4
drawable-xhdpi Bitmap占用内存:9281844 width:1287 height:1803 1像素占用大小:4
drawable-xxhdpi Bitmap占用内存:4125264 width:858 height:1202 1像素占用大小:4
drawable-xxxhdpi Bitmap占用内存:2323552 width:644 height:902 1像素占用大小:4
drawable Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4
*/
veranschaulichen:
1dp auf MDPI-Geräten1px, 1dp auf xhdpi-Geräten2px, 1dp==3px auf xxhdpi-Gerät.
Daher ist das aktuelle Gerät xxhdpi, sodass die Breite desselben Bildes unter der xxhdpi-Ressource 858 beträgt, unter der mdpi-Ressource wird es um das Dreifache vergrößert und die Breite beträgt 2574, und unter der xhdpi-Ressource wird es um das 1,5-fache vergrößert Die Breite beträgt 1287.