本文目錄一覽:
- 1、如何查看java虛擬機堆內存的參數值
- 2、Java如何實現堆棧
- 3、java中的堆棧詳解
- 4、java堆棧是啥
- 5、JAVA堆棧問題
- 6、如何理解JAVA堆棧
如何查看java虛擬機堆內存的參數值
請確保java_home/bin配置到path環境變數下,因為這些工具都在jdk的bin目錄下
jps(JVM Process Status Tool):JVM機進程狀況工具
用來查看基於HotSpot JVM裡面所有進程的具體狀態, 包括進程ID,進程啟動的路徑等等。與unix上的ps類似,用來顯示本地有許可權的java進程,可以查看本地運行著幾個java程序,並顯示他們的進程號。使用jps時,不需要傳遞進程號做為參數。
Jps也可以顯示遠程系統上的JAVA進程,這需要遠程服務上開啟了jstat服務,以及RMI注及服務,不過常用都是對本對的JAVA進程的查看。
命令格式:jps [ options ] [ hostid ]
常用參數說明:
-m 輸出傳遞給main方法的參數,如果是內嵌的JVM則輸出為null。
-l 輸出應用程序主類的完整包名,或者是應用程序JAR文件的完整路徑。
-v 輸出傳給JVM的參數。
例如:
C:\Users\Administratorjps -lmv
1796 -Dosgi.requiredJavaVersion=1.5 -Xms40m -Xmx512m -XX:MaxPermSize=256m
7340 sun.tools.jps.Jps -lmv -Denv.class.path=.;D:\DevTools\VM\jdk1.6.0_31\\lib\dt.jar;D:\DevTools\VM\jdk1.6.0_31\\lib\tools.jar; -Dapplication.home=D:\DevTools\VM\jdk1.6.0_31 -Xms8m
其中pid為1796的是我的eclipse進程,pid為7340的是jps命令本身的進程
jinfo(Configuration Info for Java):JVM配置信息工具
可以輸出並修改運行時的java 進程的opts。用處比較簡單,用於輸出JAVA系統參數及命令行參數
命令格式:jinfo [ options ] [ pid ]
常用參數說明:
-flag 輸出,修改,JVM命令行參數
例如:
C:\Users\Administratorjinfo 1796
將會列印出很多jvm運行時參數信息,由於比較長這裡不再列印出來,可以自己試試,內容一目了然
Jstack(Stack Trace for Java):JVM堆棧跟蹤工具
jstack用於列印出給定的java進程ID或core file或遠程調試服務的Java堆棧信息,如果是在64位機器上,需要指定選項”-J-d64「
命令格式:jstack [ option ] pid
常用參數說明:
-F 當』jstack [-l] pid』沒有相應的時候強制列印棧信息
-l 長列表. 列印關於鎖的附加信息,例如屬於java.util.concurrent的ownable synchronizers列表.
-m 列印java和native c/c++框架的所有棧信息.
-h | -help列印幫助信息
例如:
C:\Users\Administratorjstack 1796
2013-05-22 11:42:38
Full thread dump Java HotSpot(TM) Client VM (20.6-b01 mixed mode):
“Worker-30” prio=6 tid=0x06514c00 nid=0x1018 in Object.wait() [0x056af000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
– locked 0x1ad84a90 (a org.eclipse.core.internal.jobs.WorkerPool)
at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)
……
……
……
……
jstat(JVM statistics Monitoriing Tool):JVM統計信息監視工具
對Java應用程序的資源和性能進行實時的命令行的監控,包括了對Heap size和垃圾回收狀況的監控
命令格式:jstat [ option pid [interval [ s | ms ] [count] ] ]
常用參數說明:
-gcutil 輸出已使用空間佔總空間的百分比
-gccapacity 輸出堆中各個區域使用到的最大和最小空間
例如:每隔1秒監控jvm內存一次,共監控5次
C:\Users\Administratorjstat -gccapacity 1796 1s 5
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC PGCMN PGCMX PGC PC YGC FGC
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 96
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 96
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 96
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 96
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 97
C:\Users\Administratorjstat -gcutil 1796 1s 5
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
一些術語的中文解釋:
S0C:年輕代中第一個survivor(倖存區)的容量 (位元組)
S1C:年輕代中第二個survivor(倖存區)的容量 (位元組)
S0U:年輕代中第一個survivor(倖存區)目前已使用空間 (位元組)
S1U:年輕代中第二個survivor(倖存區)目前已使用空間 (位元組)
EC:年輕代中Eden(伊甸園)的容量 (位元組)
EU:年輕代中Eden(伊甸園)目前已使用空間 (位元組)
OC:Old代的容量 (位元組)
OU:Old代目前已使用空間 (位元組)
PC:Perm(持久代)的容量 (位元組)
PU:Perm(持久代)目前已使用空間 (位元組)
YGC:從應用程序啟動到採樣時年輕代中gc次數
YGCT:從應用程序啟動到採樣時年輕代中gc所用時間(s)
FGC:從應用程序啟動到採樣時old代(全gc)gc次數
FGCT:從應用程序啟動到採樣時old代(全gc)gc所用時間(s)
GCT:從應用程序啟動到採樣時gc用的總時間(s)
NGCMN:年輕代(young)中初始化(最小)的大小 (位元組)
NGCMX:年輕代(young)的最大容量 (位元組)
NGC:年輕代(young)中當前的容量 (位元組)
OGCMN:old代中初始化(最小)的大小 (位元組)
OGCMX:old代的最大容量 (位元組)
OGC:old代當前新生成的容量 (位元組)
PGCMN:perm代中初始化(最小)的大小 (位元組)
PGCMX:perm代的最大容量 (位元組)
PGC:perm代當前新生成的容量 (位元組)
S0:年輕代中第一個survivor(倖存區)已使用的占當前容量百分比
S1:年輕代中第二個survivor(倖存區)已使用的占當前容量百分比
E:年輕代中Eden(伊甸園)已使用的占當前容量百分比
O:old代已使用的占當前容量百分比
P:perm代已使用的占當前容量百分比
S0CMX:年輕代中第一個survivor(倖存區)的最大容量 (位元組)
S1CMX :年輕代中第二個survivor(倖存區)的最大容量 (位元組)
ECMX:年輕代中Eden(伊甸園)的最大容量 (位元組)
DSS:當前需要survivor(倖存區)的容量 (位元組)(Eden區已滿)
TT: 持有次數限制
MTT : 最大持有次數限制
jmap( Memory Map for Java):JVM內存映像工具
列印出某個java進程(使用pid)內存內的所有『對象』的情況(如:產生那些對象,及其數量)
命令格式:jmap [ option ] pid
常用參數說明:
-dump:[live,]format=b,file=filename 使用二進位形式輸出jvm的heap內容到文件中, live子選項是可選的,假如指定live選項,那麼只輸出活的對象到文件.
-histo[:live] 列印每個class的實例數目,內存佔用,類全名信息. VM的內部類名字開頭會加上前綴」*」. 如果live子參數加上後,只統計活的對象數量.
-F 強迫.在pid沒有相應的時候使用-dump或者-histo參數. 在這個模式下,live子參數無效.
例如:以二進位形式輸入當前堆內存映像到文件data.hprof中
jmap -dump:live,format=b,file=data.hprof 1796
生成的文件可以使用jhat工具進行分析,在OOM(內存溢出)時,分析大對象,非常有用
通過使用如下參數啟動JVM,也可以獲取到dump文件:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./java_pidpid.hprof
在jvm發生內存溢出時生成內存映像文件
jhat(JVM Heap Analysis Tool):JVM堆轉儲快照分析工具
用於對JAVA heap進行離線分析的工具,他可以對不同虛擬機中導出的heap信息文件進行分析,如LINUX上導出的文件可以拿到WINDOWS上進行分析,可以查找諸如內存方面的問題。
命令格式:jhat dumpfile(jmap生成的文件)
例如:分析jmap導出的內存映像
jhat data.hprof
執行成功後,訪問即可查看內存信息,
MAT(Memory Analyzer Tool):一個基於Eclipse的內存分析工具
官網:
update:
這是eclipse的一個插件,安裝後可以打開xxx.hprof文件,進行分析,比jhat更方便使用,有些時候由於線上xxx.hprof文件過大,直接使用jhat進行初步分析了,可以的話拷貝到本地分析效果更佳。
圖形化監控工具:
在JDK安裝目錄bin下面有兩個可視化監控工具
1. JConsole(Java Monitoring and Management Console) 基於JMX的可視化管理工具。
2. VisualVM(All-in-one Java Troubleshooting Tool)隨JDK發布的最強大的運行監視和故障處理程序。
推薦使用VisualVM,他有很多插件,可以更方便的監控運行時JVM
Java如何實現堆棧
//這是JDK提供的棧
import java.util.Stack;
public class UsingStack {
public static void main(String[] args) {
//構造棧對象,使用類型限制,只能存儲Integer數據
StackInteger s = new StackInteger();
//1、2、3依次入棧
s.push(1);
s.push(2);
s.push(3);
//3、2、1依次出棧
System.out.println(s.pop());
System.out.println(s.pop());
System.out.println(s.pop());
}
}
//這是我寫的順序結構的棧
import java.util.EmptyStackException;
import java.util.Vector;
public class UsingStack{
public static void main(String[] args){
//構造棧對象,使用類型限制,只能存儲Integer數據
MyStackInteger s = new MyStackInteger();
//1、2、3依次入棧
s.push(1);
s.push(2);
s.push(3);
//3、2、1依次出棧
System.out.println(s.pop());
System.out.println(s.pop());
System.out.println(s.pop());
}
}
/**
* 棧類
* @author developer_05
* @param T
*/
class MyStackT extends VectorT{
/**
* 構造方法
*/
public MyStack(){
}
/**
* 入棧方法
* @param item 待入棧的元素
* @return 返回入棧的元素
*/
public T push(T item) {
addElement(item);
return item;
}
/**
* 出棧方法(同步處理)
* @return 返回出棧元素
*/
public synchronized T pop() {
T obj;
int len = size();
if (len == 0)
throw new EmptyStackException();
obj = elementAt(len – 1);
removeElementAt(len – 1);
return obj;
}
/**
* 判斷棧是否為空的方法
* @return 返回true(棧空)或false(棧非空)
*/
public boolean empty() {
return size() == 0;
}
private static final long serialVersionUID = 1L;
}
java中的堆棧詳解
簡單的說 其實 棧 就是存放變數引用的一個地方, 堆 就是存放實際對象的地方 也就是.
比如: int i = 7; 這個 其實是存在棧裡邊的。內容為 i = 7。
Apple app = new Apple(); 這個 app 是在棧裡邊的 他對應的是一個內存地址也在堆裡邊, 而這個內存地址對應的是堆裡邊存放 Apple 實例的地址。
String s = “Hello World!”; 這個其實是存在另外一塊靜態代碼區。
總體來說: 棧–主要存放引用 和基本數據類型。
堆–用來存放 new 出來的對象實例。
java堆棧是啥
Java中堆棧的概念是邏輯上的,在完全符合Java規範的Java處理器面世之前,所有Java虛擬機提供的內容都是由軟體模擬出來的。 什麼叫堆?你用十幾個麻將牌豎直疊成一摞這叫堆,你可以從上面、下面、中間任意抽出一張牌,也可以任意插入一張。 什麼叫棧?AK-47的彈匣就是一個棧,在上面的子彈沒被取出之前,你無法取出下面的子彈——儘管你可以從邊上的透明部分讀出裡面裝的是什麼型號、顏色的子彈。 堆很靈活,但是不安全。對於對象,我們要動態地創建、銷毀,不能說後創建的對象沒有銷毀,先前創建的對象就不能銷毀,那樣的話我們的程序就寸步難行,所以Java中用堆來存儲對象。而一旦堆中的對象被銷毀,我們繼續引用這個對象的話,就會出現著名的NullPointerException,這就是堆的缺點——錯誤的引用邏輯只有在運行時才會被發現。 棧不靈活,但是很嚴格,是安全的,易於管理。因為只要上面的引用沒有銷毀,下面引用就一定還在,所以,在棧中,上面引用永遠可以通過下面引用來查找對象,同時如果確認某一區間的內容會一起存在、一起銷毀,也可以上下互相引用。在大部分程序中,都是先定義的變數、引用先進棧,後定義的後進棧,同時,區塊內部的變數、引用在進入區塊時壓棧,區塊結束時出棧,理解了這種機制,我們就可以很方便地理解各種編程語言的作用域的概念了,同時這也是棧的優點——錯誤的引用邏輯在編譯時就可以被發現。 在Java中,引用可以理解為一個永遠指向對象的指針,Java沒有指向指針的指針。 關於堆棧的資料幾乎每個講數據結構的書上都有,而至於Java中堆、棧的具體機制你可以參考一些關於Java虛擬機原理的書,不過這個好像比較難理解,我是沒指望理解的了。 以上都是我的個人觀點,僅供參考。
JAVA堆棧問題
其實這些基礎的東西網上有不少,
你可以多去csdn,那裡可以學到不少好東西
,我就直接給你粘貼過來了
java中堆棧(stack)和堆(heap)
一、堆棧(stack)和堆(heap)?
(1)內存分配的策略
按照編譯原理的觀點,程序運行時的內存分配有三種策略,分別是靜態的,棧式的,和堆式的.
靜態存儲分配是指在編譯時就能確定每個數據目標在運行時刻的存儲空間需求,因而在編譯時就可以給他們分配固定的內存空間.這種分配策略要求程序代碼中不允許有可變數據結構(比如可變數組)的存在,也不允許有嵌套或者遞歸的結構出現,因為它們都會導致編譯程序無法計算準確的存儲空間需求.
棧式存儲分配也可稱為動態存儲分配,是由一個類似於堆棧的運行棧來實現的.和靜態存儲分配相反,在棧式存儲方案中,程序對數據區的需求在編譯時是完全未知的,只有到運行的時候才能夠知道,但是規定在運行中進入一個程序模塊時,必須知道該程序模塊所需的數據區大小才能夠為其分配內存.和我們在數據結構所熟知的棧一樣,棧式存儲分配按照先進後出的原則進行分配。
靜態存儲分配要求在編譯時能知道所有變數的存儲要求,棧式存儲分配要求在過程的入口處必須知道所有的存儲要求,而堆式存儲分配則專門負責在編譯時或運行時模塊入口處都無法確定存儲要求的數據結構的內存分配,比如可變長度串和對象實例.堆由大片的可利用塊或空閑塊組成,堆中的內存可以按照任意順序分配和釋放.
(2)堆和棧的比較
上面的定義從編譯原理的教材中總結而來,除靜態存儲分配之外,都顯得很呆板和難以理解,下面撇開靜態存儲分配,集中比較堆和棧:
從堆和棧的功能和作用來通俗的比較,堆主要用來存放對象的,棧主要是用來執行程序的.而這種不同又主要是由於堆和棧的特點決定的:
在編程中,例如C/C++中,所有的方法調用都是通過棧來進行的,所有的局部變數,形式參數都是從棧中分配內存空間的。實際上也不是什麼分配,只是從棧頂向上用就行,就好像工廠中的傳送帶(conveyor
belt)一樣,Stack
Pointer會自動指引你到放東西的位置,你所要做的只是把東西放下來就行.退出函數的時候,修改棧指針就可以把棧中的內容銷毀.這樣的模式速度最快,當然要用來運行程序了.需要注意的是,在分配的時候,比如為一個即將要調用的程序模塊分配數據區時,應事先知道這個數據區的大小,也就說是雖然分配是在程序運行時進行的,但是分配的大小多少是確定的,不變的,而這個”大小多少”是在編譯時確定的,不是在運行時.
堆是應用程序在運行的時候請求操作系統分配給自己內存,由於從操作系統管理的內存分配,所以在分配和銷毀時都要佔用時間,因此用堆的效率非常低.但是堆的優點在於,編譯器不必知道要從堆里分配多少存儲空間,也不必知道存儲的數據要在堆里停留多長的時間,因此,用堆保存數據時會得到更大的靈活性。事實上,面向對象的多態性,堆內存分配是必不可少的,因為多態變數所需的存儲空間只有在運行時創建了對象之後才能確定.在C++中,要求創建一個對象時,只需用new命令編製相關的代碼即可。執行這些代碼時,會在堆里自動進行數據的保存.當然,為達到這種靈活性,必然會付出一定的代價:在堆里分配存儲空間時會花掉更長的時間!這也正是導致我們剛才所說的效率低的原因,看來列寧同志說的好,人的優點往往也是人的缺點,人的缺點往往也是人的優點(暈~).
(3)JVM中的堆和棧
JVM是基於堆棧的虛擬機.JVM為每個新創建的線程都分配一個堆棧.也就是說,對於一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。
我們知道,某個線程正在執行的方法稱為此線程的當前方法.我們可能不知道,當前方法使用的幀稱為當前幀。當線程激活一個Java方法,JVM就會在線程的Java堆棧里新壓入一個幀。這個幀自然成為了當前幀.在此方法執行期間,這個幀將用來保存參數,局部變數,中間計算過程和其他數據.這個幀在這裡和編譯原理中的活動紀錄的概念是差不多的.
從Java的這種分配機制來看,堆棧又可以這樣理解:堆棧(Stack)是操作系統在建立某個進程時或者線程(在支持多線程的操作系統中是線程)為這個線程建立的存儲區域,該區域具有先進後出的特性。
每一個Java應用都唯一對應一個JVM實例,每一個實例唯一對應一個堆。應用程序在運行中所創建的所有類實例或數組都放在這個堆中,並由應用所有的線程共享.跟C/C++不同,Java中分配堆內存是自動初始化的。Java中所有對象的存儲空間都是在堆中分配的,但是這個對象的引用卻是在堆棧中分配,也就是說在建立一個對象時從兩個地方都分配內存,在堆中分配的內存實際建立這個對象,而在堆棧中分配的內存只是一個指向這個堆對象的指針(引用)而已。
如何理解JAVA堆棧
Java的堆是一個運行時數據區,類的(對象從中分配空間。這些對象通過new、newarray、anewarray和multianewarray等 指令建立,它們不需要程序代碼來顯式的釋放。堆是由垃圾回收來負責的,堆的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,因為它是在運行時 動態分配內存的,Java的垃圾收集器會自動收走這些不再使用的數據。但缺點是,由於要在運行時動態分配內存,存取速度較慢。
棧的優勢是,存取速度比堆要快,僅次於寄存器,棧數據可以共享。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。棧中主要存放一些基本類 型的變數(,int, short, long, byte, float, double, boolean, char)和對象句柄。
棧有一個很重要的特殊性,就是存在棧中的數據可以共享。假設我們同時定義:
int a = 3;
int b = 3;
編譯器先處理int a = 3;首先它會在棧中創建一個變數為a的引用,然後查找棧中是否有3這個值,如果沒找到,就將3存放進來,然後將a指向3。接著處理int b = 3;在創建完b的引用變數後,因為在棧中已經有3這個值,便將b直接指向3。這樣,就出現了a與b同時均指向3的情況。
這時,如果再令a=4;那麼編譯器會重新搜索棧中是否有4值,如果沒有,則將4存放進來,並令a指向4;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。
要注意這種數據的共享與兩個對象的引用同時指向一個對象的這種共享是不同的,因為這種情況a的修改並不會影響到b, 它是由編譯器完成的,它有利於節省空間。而一個對象引用變數修改了這個對象的內部狀態,會影響到另一個對象引用變數。
String是一個特殊的包裝類數據。可以用:
String str = new String(“abc”);
String str = “abc”;
兩種的形式來創建,第一種是用new()來新建對象的,它會在存放於堆中。每調用一次就會創建一個新的對象。
而第二種是先在棧中創建一個對String類的對象引用變數str,然後查找棧中有沒有存放”abc”,如果沒有,則將”abc”存放進棧,並令str指向」abc」,如果已經有」abc」 則直接令str指向「abc」。
比較類裡面的數值是否相等時,用equals()方法;當測試兩個包裝類的引用是否指向同一個對象時,用==,下面用例子說明上面的理論。
String str1 = “abc”;
String str2 = “abc”;
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一個對象的。
String str1 =new String (“abc”);
String str2 =new String (“abc”);
System.out.println(str1==str2); // false
用new的方式是生成不同的對象。每一次生成一個。
因此用第一種方式創建多個」abc」字元串,在內存中其實只存在一個對象而已. 這種寫法有利與節省內存空間. 同時它可以在一定程度上提高程序的運行速度,因為JVM會自動根據棧中數據的實際情況來決定是否有必要創建新對象。而對於String str = new String(“abc”);的代碼,則一概在堆中創建新對象,而不管其字元串值是否相等,是否有必要創建新對象,從而加重了程序的負擔。
另一方面, 要注意: 我們在使用諸如String str = “abc”;的格式定義類時,總是想當然地認為,創建了String類的對象str。擔心陷阱!對象可能並沒有被創建!而可能只是指向一個先前已經創建的 對象。只有通過new()方法才能保證每次都創建一個新的對象。
由於String類的immutable性質,當String變數需要經常變換其值時,應該考慮使用StringBuffer類,以提高程序效率。
原創文章,作者:TYYR,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/135658.html