私の連絡先情報
郵便メール:
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
メモリ スラッシングとは、短期間に大量のオブジェクトが作成および破棄されることを指し、その結果、ガベージ コレクション (ガベージ コレクション、GC) アクティビティが頻繁に発生します。この頻繁な GC アクティビティは大量の CPU リソースを消費し、アプリケーションの遅延やパフォーマンスの低下を引き起こす可能性があります。
パフォーマンス: メモリの曲線がギザギザになっています。
メモリ リークは、アプリケーションが不要になったオブジェクトへの参照を保持しているときに発生します。その結果、これらのオブジェクトがガベージ コレクタによってリサイクルされなくなり、解放されるはずのメモリ領域が占有されてしまいます。時間の経過とともにメモリ リークが発生すると、利用可能なメモリがどんどん減り、最終的にはアプリケーションのクラッシュやパフォーマンスの低下につながる可能性があります。
メモリ オーバーフローは、アプリケーションが追加のメモリ領域を割り当てようとしたが、割り当てるのに十分なメモリ領域がなくなったため、システムが要求を満たすことができないときに発生します。これにより通常、アプリケーションは OutOfMemoryError 例外をスローします。
Java メモリ構造: ヒープ、仮想マシン スタック、メソッド領域、プログラム カウンター、ローカル メソッド スタック。
Java メモリ リサイクル アルゴリズム:
マーククリア アルゴリズムの欠点: マークとクリアは効率的ではなく、大量の不連続なメモリ フラグメントが生成されます。
レプリケーション アルゴリズム: 実装が簡単で、効率的に実行できます。デメリット:半分のスペースを無駄にしてしまう。
マークコンパクト アルゴリズム: マーククリーンによって引き起こされるメモリの断片化を回避し、コピー アルゴリズムのスペースの無駄を回避します。
Android のメモリの柔軟な割り当て、割り当て値、および最大値は、特定のデバイスの影響を受けます。
Dalvik リサイクル アルゴリズムと ART リサイクル アルゴリズムは、どちらも Android オペレーティング システムのメモリ管理に使用されるガベージ コレクション メカニズムです。
Dalvik リサイクル アルゴリズム:
アートリサイクルアルゴリズム:
LMK メカニズム:
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);
}
}
メモリ プロファイラーでメモリ割り当てを表示するには、[Java/Kotlin 割り当ての記録] をクリックします。
上記の意味:
以下の意味:
malloc()
またはnew
オペレーターによって割り当てられたオブジェクトの数。free()
またはdelete
オペレーターによって割り当てが解除されたオブジェクトの数。上の写真の分析:
この領域の割り当てと割り当て解除の値は比較的似ており、浅いサイズは比較的大きく、オブジェクトが頻繁に作成および破棄される可能性があることを示しています。
クリックするとコール スタック情報が表示され、コードと組み合わせると、ハンドラーにメモリ ジッターの問題があると推測できます。
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() {
}
}
依存ライブラリを追加します。
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
メモリ リークが発生すると、LeakCanary は関連情報を生成し、自動的にダンプします。
上の図からわかるように、LeakActivity にはメモリ リークがあり、参照チェーン関係が表示されます。
もちろん、hprof ファイルを生成し、プロファイラー ツールを使用して特定の情報を表示することもできます。
上の図からわかるように、LeakActivity を含む 10 個のリーク ポイントが発生しています。LeakActivity をクリックしてメモリ リーク オブジェクトを表示し、それが ArrayList によって保持されていることがわかります。
Bitmap を使用した後、画像リソースを解放しないと、次のような問題が発生しやすくなります。メモリリークによるメモリオーバーフロー。
メモリのリサイクル:
Bitmap.recycle()
ビットマップのリサイクルを実行します。ビットマップピクセル構成:
設定 | 占有バイトサイズ(バイト) | 説明する |
---|---|---|
アルファ_8 | 1 | 単一の透明チャネル |
565色 | 2 | シンプルなRGB色合い |
ARGB_8888 | 4 | 24ビットトゥルーカラー |
RGBA_F16 | 8 | Android 8.0 新 (HDR) |
Btimap が占有するメモリを計算します。
リソースファイルの問題:
テストコード:
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
*/
例証します:
mdpi デバイスでは 1dpxhdpi デバイスでは 1px、1dpxxhdpi デバイスでは 2px、1dp==3px。
したがって、現在のデバイスは xxhdpi であるため、xxhdpi リソースの下では同じ画像の幅は 858、mdpi リソースの下では 3 倍に拡大され、幅は 2574、xhdpi リソースの下では 1.5 倍に拡大され、幅は 2574 になります。幅は1287です。