關于作者:CSDN內容合伙人、技術專家, 從零開始做日活千萬級APP。
專注于分享各領域原創系列文章 ,擅長java后端、移動開發、人工智能等,希望大家多多支持。
目錄
- 一、導讀
- 二、概覽
- 三、案例分析
- 3.1 使用memory-profiler
- 3.2 使用 cpu-profiler
- 四、 推薦閱讀
一、導讀
我們繼續總結學習Java基礎知識,溫故知新。
二、概覽
內存抖動是指內存不穩定,頻繁分配和回收,導致內存不穩定,其表現形式為頻繁GC,
內存抖動可能會導致以下問題:
- 性能下降:由于頻繁的內存分配和回收操作,系統的性能會受到影響,導致運行速度變慢。
- 程序崩潰、OOM:內存抖動可能導致內存分配錯誤或者內存泄漏,導致程序崩潰或者運行不穩定。
- 系統資源消耗:內存抖動會增加系統資源的消耗,包括內存和CPU的占用率,可能導致系統負載增加。
內存抖動大部分都是由于頻繁創建對象導致,會占用大量內存,同時會產生大量的內存碎片,不連續的內存碎片很多情況下是無法被分配的。
從而導致OOM的產生。
要防止內存抖動,可以采取以下幾個方法和策略:
-
合理規劃內存分配:在設計和編寫代碼時,要合理規劃內存的分配和釋放,避免頻繁的內存分配和回收操作。可以使用對象池、緩沖區等技術來預先分配和管理一塊內存,減少內存分配的開銷。
-
避免內存碎片:內存碎片是指內存中存在一些被分割成小塊的未被使用的空間。內存碎片會導致內存分配失敗或效率低下。可以通過使用內存池、內存復用等方法來減少內存碎片的產生。另外,考慮使用內存管理工具或垃圾回收機制來自動進行內存碎片整理和回收。
-
優化算法和數據結構:一些算法和數據結構可能會導致內存抖動,例如頻繁的動態數組擴容和收縮操作。可以使用更合適的數據結構或算法,降低內存抖動的概率或頻率。比如使用鏈表代替數組,使用平衡二叉樹代替線性查找等。
-
設置適當的內存分配策略:根據實際情況,可以根據內存使用情況和需求,設置合適的內存分配策略。可以使用內存池、內存緩存等技術來預先分配和管理內存,減少頻繁的內存分配與回收操作。
-
進行內存性能優化:對于大型或長時間運行的應用程序,可以進行內存性能優化。可以使用內存分析工具和性能分析工具來檢測內存使用情況,找出內存抖動的原因,并針對性地進行優化。
-
進行定期的內存測試和性能評估:定期進行內存測試和性能評估,可以發現潛在的內存抖動問題,并進行及時修復和優化。
三、案例分析
不同的工具有不同的使用場景,對應線下場景,我們先用 android studio自帶的工具
3.1 使用memory-profiler
可以直觀的展示內存使用情況,我們先上一段代碼,來模擬內存申請及釋放
public class MainActivity extends AppCompatActivity {// Used to load the 'example' library on application startup.static {System.loadLibrary("example");}private static Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);// 循環1000次for (int index = 0; index <= 1000; index++){// 然后弄一個相對耗內存的操作,制造內存抖動String args[] = new String[1000000];}mHandler.sendEmptyMessageDelayed(0,50);}};private ActivityMainBinding binding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());// Example of a call to a native methodTextView tv = binding.sampleText;tv.setText(stringFromJNI());tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mHandler.sendEmptyMessageDelayed(0,2000);}});}/*** A native method that is implemented by the 'example' native library,* which is packaged with this application.*/public native String stringFromJNI();
}
代碼運行后,我們進行內存的保存,快速查看Java 和 Kotlin 分配情況分析
通過上面的圖,我們可以看到在頻繁的gc,
那我們怎么才能知道內存抖動真正發生在哪里呢,看上圖,string數組非常多,我們點一下這個string數組,如下圖:
上面就出現了一個Call Stack 標簽頁,顯示該實例被分配到何處以及在哪個線程中,我們可以明顯的看到 handlemessage,
然后右鍵選擇jump to source,之間跳轉到源碼查看。
Allocations: 此類創建的實例對象數量
Total count:對象在堆中未被回收的數量
3.2 使用 cpu-profiler
使用方式跟上面差不錯,我們保存文件,然后查看,
跟蹤這一段CPU執行的時間,
如果發現某一段(應用自有函數的調用)代碼(即綠色的條形段)在反復地被執行,便是內存抖動的地方
四、 推薦閱讀
Java 專欄
SQL 專欄
數據結構與算法
Android學習專欄