計算機中每個操作系統(tǒng)給每個進程的內(nèi)存是有限制的(windows64位系統(tǒng)中最大分配內(nèi)存是2G),即對于虛擬機,最大內(nèi)存是2G,不算虛擬機進程啟動時所占用的內(nèi)存,剩下的內(nèi)存分配給共享區(qū)和線程獨享區(qū),共享區(qū)的內(nèi)存大小由虛擬機參數(shù)(-Xmx最大堆內(nèi)存,MaxPermSize最大方法區(qū)容量)指定,剩下的則分配給??臻g,程序計數(shù)器占用的空間極小可忽略不計,每個線程分配到的棧容量越大,可以建立的線程的數(shù)量自然就越少,建立線程時則更容易將內(nèi)存耗盡。
測試:
public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak(){
stackLength ++;
stackLeak();
}
public static void main(String[] args) {
JavaVMStackSOF oom = new JavaVMStackSOF();
try {
oom.stackLeak();
}catch (Throwable e){
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
設置虛擬機參數(shù):
-Xss128k :設置每個線程的棧大小,減小這個值,可以使虛擬機創(chuàng)建更多線程
運行結果:
stack length:967
Exception in thread "main" java.lang.StackOverflowError
at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:11)
at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
at com.example.stackoverflowerror.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
...
報出虛擬機棧超出虛擬機允許的最大深度的錯誤(StackOverflowError)。
通過-Xss控制了每個線程的最大棧大小,當棧不斷增大時,會暴露??臻g不足的錯誤,這種錯誤有兩種,一種是上述的棧深度超出,個人理解應該跟數(shù)組的outOfIndexError差不多的意思。
另一種就是虛擬機為棧分配的空間不足了,造成內(nèi)存溢出。
代碼:
public class JavaVMStackOOM {
private void dontStop(){
while (true){
}
}
public void stackLeakByThread(){
while (true){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) {
JavaVMStackOOM javaVMStackOOM = new JavaVMStackOOM();
javaVMStackOOM.stackLeakByThread();
}
}
設置虛擬機參數(shù):
-Xss2m 將每個線程分配的空間調(diào)大一些
由于java線程是映射到操作系統(tǒng)的內(nèi)核線程上的,因此上述代碼執(zhí)行有較大風險,可能會導致操作系統(tǒng)假死。本人測試的時候就死機了。。。