詳談jvm線程??臻g內(nèi)存分配位置
jvm線程??臻g內(nèi)存分配位置
jvm的線程棧申請的內(nèi)存空間屬于堆外內(nèi)存,是向操作系統(tǒng)申請的,也不是JVM直接內(nèi)存,雖然類似。
JVM能創(chuàng)建的線程數(shù)需要的內(nèi)存,不是JVM運行內(nèi)存,堆內(nèi)存,直接內(nèi)存,而是操作系統(tǒng)剩余的可用內(nèi)存,這個也決定了能創(chuàng)建的線程數(shù),如果內(nèi)存不夠用,創(chuàng)建線程的時候便會出現(xiàn)內(nèi)存溢出的錯誤。
在操作系統(tǒng)的可用內(nèi)存不足的情況下,想要創(chuàng)建更多的線程,可以考慮減少線程棧的空間大小(-Xss),但是不建議過小,棧嘗試減小容易棧溢出錯誤。
--------------------------分割線--------------------------
后來有次早上5點睡不著,起床做了個測試驗證,在這里補充下這個測試說明,當(dāng)時只是發(fā)了個朋友圈,過得有點久了現(xiàn)在我也只從手機上找到幾張圖片貼上來:
JVM配置如下
設(shè)置最大堆10m,線程棧大小10m,直接內(nèi)存5m。
創(chuàng)建1000條線程,調(diào)用10w次函數(shù)(調(diào)用次數(shù)再過多,棧深不夠就溢出了),瘋狂壓棧但不出棧(遞歸調(diào)用)。然后看內(nèi)存,物理內(nèi)存占用7g多,有次是5g多。沒有堆溢出,也沒有直接內(nèi)存溢出。說明線程棧內(nèi)存在堆外分配,不屬于堆內(nèi)存(線程對象還是分配在堆內(nèi)存空間),也不屬于直接內(nèi)存部分。
測試截的一些圖片如下
JVM配置

main方法創(chuàng)建1條線程并運行:

main方法創(chuàng)建1000條線程并運行:

測試代碼
/**
* @Auther: 許曉東
* @Date: 19-8-3 05:14
* @Description:
*/
public class ThreadStackTest {
static Map<Integer, Thread> map = new HashMap<>();
static Runnable runnable = new Runnable() {
@Override
public void run() {
try {
recursive(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
private static void recursive(int num) throws InterruptedException {
if (num == 20000) {
Thread.sleep(Integer.MAX_VALUE);
}else {
recursive(++num);
}
}
public static void main(String[] args) throws InterruptedException {
System.gc();
int nums = 1000;
//int nums = 1;
for (int i = 0; i < nums; i++) {
map.put(i, new Thread(runnable));
}
for (Thread thread :
map.values()) {
thread.start();
}
System.out.println(String.format("創(chuàng)建%d條線程后gc情況:", nums));
System.gc();
Thread.sleep(Integer.MAX_VALUE);
}
}
jvm棧大小設(shè)置
1、棧內(nèi)存大小設(shè)置
棧內(nèi)存為線程私有的空間,每個線程都會創(chuàng)建私有的棧內(nèi)存。??臻g內(nèi)存設(shè)置過大,創(chuàng)建線程數(shù)量較多時會出現(xiàn)棧內(nèi)存溢出StackOverflowError。同時,棧內(nèi)存也決定方法調(diào)用的深度,棧內(nèi)存過小則會導(dǎo)致方法調(diào)用的深度較小,如遞歸調(diào)用的次數(shù)較少。
-Xss:如-Xss128k
通常只有幾百K
決定了函數(shù)調(diào)用的深度
每個線程都有獨立的??臻g
局部變量、參數(shù) 分配在棧上
2、遞歸調(diào)用
package com.thread.study;
public class Stack {
private static int count=0;
public static void recursion(long a,long b,long c){
long e=1,f=2,g=3,h=4,i=5,k=6,q=7,x=8,y=9,z=10;
count++;
recursion(a,b,c);
}
public static void main(String args[]){
try{
recursion(0L,0L,0L);
}catch(Throwable e){
System.out.println("deep of calling = "+count);
e.printStackTrace();
}
}
}
- -Xss128k:deep of calling = 306
- -Xss256k:deep of calling = 761
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
idea運行main方法或Test避免編譯整個應(yīng)用的實現(xiàn)方法
這篇文章主要介紹了idea運行main方法或Test避免編譯整個應(yīng)用的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04
Java導(dǎo)入新項目報錯java:JDK?isn‘t?specified?for?module解決辦法
這篇文章主要給大家介紹了關(guān)于Java導(dǎo)入新項目報錯java:JDK?isn‘t?specified?for?module的解決辦法,當(dāng)您在導(dǎo)入Java項目時遇到錯誤時,可以嘗試以下面的方法來處理,需要的朋友可以參考下2024-05-05
為什么在重寫 equals方法的同時必須重寫 hashcode方法
Object 類是所有類的父類,其 equals 方法比較的是兩個對象的引用指向的地址,hashcode 是一個本地方法,返回的是對象地址值。他們都是通過比較地址來比較對象是否相等的2016-07-07
關(guān)于@Transactional事務(wù)表被鎖的問題及解決
這篇文章主要介紹了關(guān)于@Transactional事務(wù)表被鎖的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01

