JAVA的堆疊和記憶體、垃圾回收解說
1.有關java健壯性特點的真相
很多書上都說java健壯性的特點是因為java使用陣列代替了c++的指標;c++最令人頭痛的問題就是記憶體問題,java的健壯性使程式設計人員不用再考慮記憶體的問題;這種觀點和想法是不對,java雖然有垃圾回收機制,不需要程式設計師去delete記憶體,但是在編碼的時候還是應該考慮到記憶體的,儘量不要去浪費jvm的記憶體;這裡就涉及到了java的堆疊問題。
2.java堆疊的區別
堆:存放類型別,用new建立,垃圾自動回收機制負責回收,速度慢
1).堆是一個“執行時”資料區,類例項化物件是從堆上去分配空間的,也就是說堆上空間都是通過new指令建立的;
2).與c++的區別就是java不需要顯示的去釋放堆,而是由垃圾回收機制負責,這是因為堆是動態分配記憶體大小的,即程式執行的時候分配;
3).這也產生了一個問題,堆空間的資料記憶體讀取比較慢。
例:String str =new String(“yangkai”);
棧:存放基本資料型別,速度快
1).棧主要存放基本資料型別(byte、short、int、long、float、double、boolean、char)和物件控制程式碼;
2).資料可以共享;何為共享?這裡說的共享不是程式設計師決定的而是由jvm來控制,指系統自動處理的方式,比如說:int a = 10;int b= 10;這裡的a、b變數指向的棧上空間地址是同一個,這就是所謂的“資料共享”;jvm的處理邏輯:java虛擬機器去處理int a = 10的時候先去棧上建立一個變數作為a的引用,然後去查棧去找有沒有10的值,如果有就將a指向10,如果沒有就把10存進來。
3).相對於堆來說速度快;
4).棧資料的大小與生存期是確定的,缺乏靈活性。
例:int a = 0;
3.例項化物件的方法
比如說String這個類的例項可以由兩種方法建立:
String str = new String(“yangkai”);
String str = “yangkai”;
分析:這兩個方式建立的額物件是不同的,依照我們們上面介紹的堆疊知識應該對這種String的例項有所瞭解了吧!第一種採用new方式的在堆上開闢空間沒呼叫一次就會建立一個物件;第二種是現在棧上建立String物件的引用,然後儲存“yangkai”再讓str引用;下次再呼叫str,如果棧上有就不會再次建立了;所以一般比較String變數的時候都採用兩種方式,equals()和“==”;一般“==”判斷的是物件是否相等即是否是同一個物件;判斷出來兩個String物件相等了說明這個字串是存放在棧的,資料是共享的,這兩個字串是同一個物件;而equals()判斷兩個物件的內容是否相等,比如判斷堆上的字串的內容只能通過equals()方法來判斷,“==”判斷的可能是false,因為每一個string在堆上都是以一個String物件儲存的。
4.如何控制記憶體,這裡教你檢視jvm記憶體的使用
當前虛擬機器的最大記憶體: Runtime.getRuntime().maxMemory();
迴圈前虛擬機器已佔記憶體: Runtime.getRuntime().totalMemory();
下面使用兩個案例來監測jvm記憶體:
package com.hudong.memory;
/**
*
* @Title: MemoryTest.java
* @Copyright: Copyright (c)2005
* @Description: <br>
* <br>
* 測試java虛擬機器的記憶體佔用情況
* @Created on 2014-1-21 上午11:40:35
* @author楊凱
*/
public class MemoryTest {
/**
* @param args
*/
public static void main(String[]args) {
testStringBuffer();
// testString();
}
/**
* 測試String例項物件的佔用的記憶體
*/
public static void testString() {
String str = new String("abcdefghijklmn");
int count = 0;
System.out.println("當前虛擬機器的最大記憶體:" + Runtime.getRuntime().maxMemory()/ 1024 / 1024 + "m------" + Runtime.getRuntime().maxMemory()+ "byte");
System.out.println("迴圈前虛擬機器已佔記憶體:" + Runtime.getRuntime().totalMemory()/ 1024 / 1024 + "m====" + Runtime.getRuntime().totalMemory()+ "byte");
while (true) {
try {
str += str;
count++;
} catch (Error e) {
System.out.println("迴圈次數:" + count);
System.out.println("字串迴圈後的大小為:" + str.length() / 1024 / 1024 + "m-=-=-=" + str.length() + "byte");
System.out.println("迴圈前虛擬機器已佔記憶體:" + Runtime.getRuntime().totalMemory()/ 1024 / 1024 + "m====" + Runtime.getRuntime().totalMemory()+ "byte");
System.out.println("遇到錯誤:" + e);
break;
}
}
/*
* 執行結果:
* 當前虛擬機器的最大記憶體:793m------832438272byte
迴圈前虛擬機器已佔記憶體:127m====133234688byte
迴圈次數:23
字串迴圈後的大小為:112m-=-=-=117440512byte
迴圈前虛擬機器已佔記憶體:642m====673669120byte
遇到錯誤:java.lang.OutOfMemoryError: Java heap space
*/
}
/**
* 測試StringBuffer例項物件的佔用的記憶體
*/
public static void testStringBuffer(){
StringBuffer sb = new StringBuffer("abcdefghijklmn");
int count = 0;
System.out.println("當前虛擬機器的最大記憶體:" + Runtime.getRuntime().maxMemory()/ 1024 / 1024 + "m------" + Runtime.getRuntime().maxMemory()+ "byte");
System.out.println("迴圈前虛擬機器已佔記憶體:" + Runtime.getRuntime().totalMemory()/ 1024 / 1024 + "m====" + Runtime.getRuntime().totalMemory()+ "byte");
while (true) {
try {
sb.append(sb);
count++;
} catch (Error e) {
System.out.println("迴圈次數:" + count);
System.out.println("字串迴圈後的大小為:" + sb.length() / 1024 / 1024 + "m-=-=-=" + sb.length() + "byte");
System.out.println("迴圈前虛擬機器已佔記憶體:" + Runtime.getRuntime().totalMemory()/ 1024 / 1024 + "m====" + Runtime.getRuntime().totalMemory()+ "byte");
System.out.println("遇到錯誤:" + e);
break;
}
}
/*
* 執行結果:
* 當前虛擬機器的最大記憶體:793m------832438272byte
迴圈前虛擬機器已佔記憶體:127m====133234688byte
迴圈次數:23
字串迴圈後的大小為:112m-=-=-=117440512byte
迴圈前虛擬機器已佔記憶體:539m====566108160byte
遇到錯誤:java.lang.OutOfMemoryError: Java heap space
*/
}
}
分析:以上兩個程式用來說明String和StringBuffer兩個佔用記憶體的情況;其他資料上面介紹這兩個類的使用的時候得出的結果是:Stringbuffer比String迴圈後得到的字串位元組大;而我在這測試的時候得到結果兩個類得到的字串大小是一樣的,區別是耗費的額虛擬機器的記憶體大小不一樣,後者明顯的比前者小。
注:安裝完jdk之後jvm預設的大小是63m,上面我測試的時候是將jvm的配置檔案的xmx大小調大之後的。
相關文章
- 探索JVM的垃圾回收(堆記憶體)JVM記憶體
- 堆疊和記憶體的關係 細說記憶體
- Java 堆疊記憶體分配Java記憶體
- 【JVM之記憶體與垃圾回收篇】堆JVM記憶體
- java記憶體垃圾回收模型Java記憶體模型
- Java堆外直接記憶體回收Java記憶體
- 記憶體堆疊記憶體
- Java記憶體管理 -JVM 垃圾回收Java記憶體JVM
- JVM的記憶體管理和垃圾回收JVM記憶體
- Node - 記憶體管理和垃圾回收記憶體
- Node記憶體限制和垃圾回收記憶體
- JVM記憶體管理和垃圾回收JVM記憶體
- [Java效能剖析]Sun JVM記憶體管理和垃圾回收JavaJVM記憶體
- 【高頻Java面試題】簡單說說JVM堆的記憶體結構和GC回收流程Java面試題JVM記憶體GC
- JVM垃圾回收和記憶體分配策略JVM記憶體
- JVM原理講解和調優,記憶體管理和垃圾回收,記憶體調優JVM記憶體
- Java堆疊的深度分析及記憶體管理技巧Java記憶體
- JavaScript中的垃圾回收和記憶體洩漏JavaScript記憶體
- javascript的垃圾回收機制和記憶體管理JavaScript記憶體
- .NET記憶體管理、垃圾回收記憶體
- Java進階10 記憶體管理與垃圾回收Java記憶體
- Java記憶體模型,垃圾回收機制,常用記憶體命令及工具Java記憶體模型
- java棧記憶體和堆記憶體的詮釋Java記憶體
- 你必須瞭解的java記憶體管理機制(四)-垃圾回收Java記憶體
- JavaScript 記憶體管理及垃圾回收JavaScript記憶體
- Node記憶體限制與垃圾回收記憶體
- JS中堆疊記憶體的練習JS記憶體
- javascript堆疊記憶體分配的區別JavaScript記憶體
- JVM垃圾回收器、記憶體分配與回收策略JVM記憶體
- 託管堆和垃圾回收(GC)GC
- golang 垃圾回收器如何標記記憶體?Golang記憶體
- JVM記憶體管理和垃圾回收機制介紹JVM記憶體
- PHP 垃圾回收與記憶體管理指引PHP記憶體
- C# 垃圾回收釋放記憶體C#記憶體
- 堆記憶體和棧記憶體詳解(轉載)記憶體
- js垃圾回收機制和引起記憶體洩漏的操作JS記憶體
- 圖解Java記憶體回收機制圖解Java記憶體
- windows核心程式設計--記憶體堆疊Windows程式設計記憶體