JVM进阶

本文围绕JVM展开,介绍了常见的垃圾回收算法,如引用计数、复制、标记清除和标记整理等,还说明了GC Root的概念及判断对象是否可回收的方法。同时,详细阐述了JVM参数类型、基本配置参数,以及强引用、软引用、弱引用、虚引用的区别,最后提及了OOM的情况及解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

内存结构图

GC作用域

常见的垃圾回收算法:

①引用计数:有对象引用就加1,没对象引用就减1,到0为止回收;  双端循环引用特别容易报错;

应用:微软COM/ActionScrip3/Python...

缺点:每次对对象赋值时均要维护引用计数器,且计数器本身也有一定的消耗;  较难处理循环引用;  ===> JVM的实现一般不采用这种方式。

②复制:用在新生代;幸存者0区和幸存者1区,GC时会进行交换;复制--清空--交换; 优点是没有产生内存碎片(整体复制),缺点是有点浪费空间;

③标记清除:标记---清除,会产生碎片  ;;

④标记整理: 既不浪费空间又不产生碎片但它耗时很长;

    ③④用于老年代比较多

GC Root

内存中已经不再被使用到的空间就是垃圾;要进行垃圾回收如何判断一个对象是否可以被回收?

①引用计数法:

 Java中,引用和对象是有关联的。如果要操作对象则必须用引用进行;  通过引用计数来判断一个对象是否可以回收,即给对象添加一个引用计数器,当有一个地方引用它,计数器值加1,当有一个引用实效时,计数器值减1。任何时刻计数器值为0的对象就是不可能再被使用的,那么这个对象就是可回收对象。

但主流java虚拟机里都没采用这种算法,因为它很难解决对象之间互相循环引用的问题。(了解即可)

                       

 枚举根节点做可达性分析(根搜索路径)

为了解决引用计数法的循环引用问题,java使用了可达性分析的方法。

                       

所谓"GC Roots"或者说tracing GC的“根集合” 就是一组必须活跃的引用。

基本思路就是通过一系列名为"GC Roots"的对象作为起始点,从这个被称为GC Roots的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。也即给定一个集合的引用作为根出发,通过引用关系遍历对象图,能被遍历到的(可到达)对象就被判定为存活;没有被遍历到的就自然被判定为死亡。

可达性分析/ 根搜索路径:从GC Root开始

哪些可以作为GC Roots的对象:从它们作为垃圾扫描的起始点

  • 虚拟机栈(栈帧中的局部变量区,也叫局部变量表)中引用的对象;
  • 方法区中的类静态属性引用的对象;
  • 方法区中的常量引用的对象;
  • 本地方法栈中JNI(Native方法)引用的对象;

 2.JVM参数类型:

①标配参数(java -version、java -help、java -showversion);

②x参数(了解;-Xint解释执行、-Xcomp第一次使用就编译成本地代码、-Xmixed混合模式即先编译后执行) ;

C:\Users\Administrator>java -Xint -version
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, interpreted mode)

C:\Users\Administrator>java -Xcomp -version
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, compiled mode)
View Code

xx参数

  ③.1 Boolean类型:

  公式 -XX:+或者-某个属性值(+表示开启,-表示关闭)

  Case:①是否打印GC收集细节 -XX:-PrintGCDetails、-XX:+PrintGCDetails

     ②是否使用串行垃圾收集器:-XX:-UseSerialGC  ; -XX:+UseSerialGC

E:\20181111\javaSE\JUCJVM>jps -l
7456 sun.tools.jps.Jps
6292 org.jetbrains.idea.maven.server.RemoteMavenServer
6676 com.atguigu.jvm.gc.HelloGc
6868 org.jetbrains.jps.cmdline.Launcher

E:\20181111\javaSE\JUCJVM>jinfo -flag PrintGCDetails 6676
-XX:-PrintGCDetails

在IDEA中添加参数:
VM option: -XX:+PrintGCDetails 
再次重复上边的步骤则:
-XX:+PrintGCDetails 就已经开启了

  ③.2 kv设值类型 公式:-XX:属性key=属性值value

 

E:\20181111\javaSE\JUCJVM>jinfo -flag PrintGCDetails 7284  //在开启+PrintGCDetails之上,查看MetaspaceSize的大小,默认上22M左右
-XX:+PrintGCDetails

E:\20181111\javaSE\JUCJVM>jinfo -flag MetaspaceSize 7284
-XX:MetaspaceSize=21807104
E:\20181111\javaSE\JUCJVM>jinfo -flag  MaxTenuringThreshold 7284
-XX:MaxTenuringThreshold=15


同理可在ieda中配置参数设置它的值
-XX:MetaspaceSize=1024M
E:\20181111\javaSE\JUCJVM>jinfo -flag MetaspaceSize 8058
-XX:MetaspaceSize=1073741824

  ③.3 jinfo举例,如何查看当前运行程序的配置

    公式:jinfo -flag 配置项 进程编号    Command line是人工设置的

E:\20181111\javaSE\JUCJVM>jinfo -flags 4292
Attaching to process ID 4292, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.141-b15
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4269801472 -XX:MaxNewSize=1422917632 -XX:MetaspaceS
ize=1073741824 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops
 -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -XX:MetaspaceSize=1024M -javaagent:D:\ProgramFiles\ideaIU\ideaIU-2018.1.4\lib\idea_rt.jar=52146:D:\ProgramFiles\ideaIU\ideaIU-
2018.1.4\bin -Dfile.encoding=UTF-8  

两个经典参数:-Xms <==> -XX:InitialHeapSize;-Xmx  <==> -XX:MaxHeapSize

Xms 初始的堆空间;  Xmx 堆空间最大值  ;它俩最好调成一样,避免GC频繁的收集 忽高忽低;

Xss初始的栈空间

 盘点家底查看JVM默认值:

 -XX:+PrintFlagsInitial  
 -XX:+PrintFlagsFinal  PrintFlagsFinal举例,运行java命令的同时打印出参数
 -XX:+PrintCommandLineFlags

-Xms系统内存的1/64、-Xmx系统内存的1/4

查看初始默认值: java -XX:+PrintFlagsInitial
java -XX:+PrintFlagsFinal -version

E:\20181111\javaSE\JUCJVM>java -XX:+PrintFlagsInitial //这个参数很重要!JVM系统默认的 [Global flags] uintx AdaptiveSizeDecrementScaleFactor = 4 {product} uintx AdaptiveSizeMajorGCDecayTimeScale = 10 {product} uintx AdaptiveSizePausePolicy = 0 {product} uintx AdaptiveSizePolicyCollectionCostMargin = 50 {product} uintx AdaptiveSizePolicyInitializingSteps = 20 {product} uintx AdaptiveSizePolicyOutputInterval = 0 {product} uintx AdaptiveSizePolicyWeight = 10 {product} uintx AdaptiveSizeThroughPutPolicy = 0 {product} uintx AdaptiveTimeWeight = 25 {product} bool AdjustConcurrency = false {product} bool AggressiveOpts = false {product}

 


java -XX:+PrintFlagsFinal -version这个是会打印出JVM的版本 ;Final是修改过最终的值 ;Initial是初始默认的
                                              =是没改过, :=是人为或JVM加载不一样自己去修改过; uintx MaxHeapSize                  :
= 4269801472              {product} ##这些加:=表示修改过之后的值;没有加:表没有修改 uintx InitialHeapSize := 268435456 {product}


java -XX:+PrintFlagsFinal   -XX:MetaspaceSize=512m T(运行java类名字)


C:\Users\Administrator>java -XX:+PrintCommandLineFlags -version //主要用来查看默认的垃圾回收器 -XX:InitialHeapSize=266841920 -XX:MaxHeapSize=4269470720 -XX:+PrintCommandLineFl ags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesInd ividualAllocation -XX:+UseParallelGC //查看默认的垃圾回收器的种类 java version "1.8.0_141" Java(TM) SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)

3.JVM基本配置参数有哪些?

堆内存的初始分配

常用参数:

-Xms:初始大小内存,默认为物理内存1/64;等价于  -XX:InitialHeapSize

-Xmx:最大分配内存,默认为物理内存1/4; 等价于  -XX:MaxHeapSize

-Xss:设置单个线程栈大小,一般默认为512k--1024k  -XX:ThreadStackSize  运行时栈空间

-Xmn: 设置年轻代大小

-XX:MetaspaceSize:

典型设置案例:

-XX:+PrintGCDetails 输出详细GC收集日志信息; GC;  FullGC

-XX:SurvivorRatio:

-XX:NewRatio

-XX:MaxTenuringThreshold

E:\20181111\javaSE\JUCJVM>jinfo -flag ThreadStackSize 8852 //0表示默认配置,是根据系统的配置
-XX:ThreadStackSize=0

E:\20181111\javaSE\JUCJVM>jps -l
4560 sun.tools.jps.Jps
6292 org.jetbrains.idea.maven.server.RemoteMavenServer
3032 org.jetbrains.jps.cmdline.Launcher
5368
7192 com.atguigu.jvm.gc.HelloGc
在IDEA中配置-Xss128k 

E:\20181111\javaSE\JUCJVM>jinfo -flag ThreadStackSize 7192
-XX:ThreadStackSize=128

 

 

 -Xmm一般不调用的默认值,new 新生代 年轻代;

-XX:MetaspaceSize 

设置元空间大小,元空间本质和永久代类似,都是对JVM规范中方法区的实现;不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。

因此,默认情况下,元空间的大小仅受本地内存限制。-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m

-Xms10m -Xmx 10m  -XX:MetaspaceSize=1024m -XX:+PrintFlagsFinal 

E:\20181111\javaSE\JUCJVM>jinfo -flag MetaspaceSize 7188
-XX:MetaspaceSize=21807104  //元空间默认大小约是21M
可以自己配置;自定义

典型设置案例:

在IDEA中配置:VM options:-XX:+PrintCommandLineFlags
默认:
-XX:InitialHeapSize=266841920 
-XX:MaxHeapSize=4269470720 
-XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation 
-XX:+UseParallelGC 
************HelloWorld

-XX:+UseParallelGC 并行垃圾回收器
-XX:+UseSerialGC  串行垃圾回收器

在IDEA中配置:VM options:
-Xms128m -Xmx4096m -Xss1024k -XX:MetaspaceSize=512m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseSerialGC
-XX:InitialHeapSize=134217728 -XX:MaxHeapSize=4294967296 -XX:MetaspaceSize=536870912 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:ThreadStackSize=1024 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseSerialGC ************HelloWorld

 

************HelloWorld
//分配失败,没有空间了压缩产生了次GC
GC在新生区,Full GC在养老区
[GC (Allocation Failure) [PSYoungGen: 1960K->488K(2560K)(GC前是1960,GC后是488k,新生区总共2560K)] 1960K->768K(9728K)(GC之前堆是1960,之后是768K,9728是堆的总大小), 0.0029644 secs(GC耗时时间)] [Times: user=0.08 sys=0.00, real=0.00 secs] (GC用户时间、系统时间、GC实际时间)
[GC (Allocation Failure) [PSYoungGen: 488K->496K(2560K)] 768K->856K(9728K), 0.0031208 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

[Full GC (Allocation Failure) [PSYoungGen: 496K->0K(2560K)] [ParOldGen: 360K->640K(7168K)] 856K->640K(9728K), [Metaspace: 3439K->3439K(1056768K)], 0.0079096 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 640K->640K(9728K), 0.0004159 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 640K->621K(7168K)] 640K->621K(9728K), [Metaspace: 3439K->3439K(1056768K)], 0.0053786 secs] [Times: user=0.09 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 2560K, used 96K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 4% used [0x00000000ffd00000,0x00000000ffd183c0,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 7168K, used 621K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
  object space 7168K, 8% used [0x00000000ff600000,0x00000000ff69b7d8,0x00000000ffd00000)
 Metaspace       used 3484K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 382K, capacity 388K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

 

 

 

 -XX:SurvivorRatio

设置新生代中eden和S0/S1空间的比例,默认-XX:SurvivorRatio=8,Eden:S0:S1 = 8:1:1

假如 -XX:SurvivorRatio=4,Eden:S0:S1 = 4:1:1,SurvivorRatio值就是设置eden区的比例占多少,S0/S1相同;

Eden:S0:S1 = 8:1:1
-XX:+PrintGCDetails -XX:+UseSerialGC -Xms10m -Xmx10m -XX:SurvivorRatio=8 // -XX:SurvivorRatio=8加不加结果没影响 eden space 2752K, 74% used [0x00000000ff600000, 0x00000000ff803fe8, 0x00000000ff8b0000) from space 320K, 0% used [0x00000000ff8b0000, 0x00000000ff8b0000, 0x00000000ff900000) //320 * 8 大约= 2752 to space 320K, 0% used [0x00000000ff900000, 0x00000000ff900000, 0x00000000ff950000) tenured generation total 6848K, used 0K [0x00000000ff950000, 0x0000000100000000, 0x0000000100000000) the space 6848K, Eden:S0:S1 = 4:1:1 -XX:+PrintGCDetails -XX:+UseSerialGC -Xms10m -Xmx10m -XX:SurvivorRatio=4 eden space 2368K, 85% used [0x00000000ff600000, 0x00000000ff7f84d8, 0x00000000ff850000) from space 512K, 0% used [0x00000000ff850000, 0x00000000ff850000, 0x00000000ff8d0000) to space 512K, 0% used [0x00000000ff8d0000, 0x00000000ff8d0000, 0x00000000ff950000) tenured generation total 6848K, used 0K [0x00000000ff950000, 0x0000000100000000, 0x0000000100000000) the space 6848K,

 

 -XX:NewRatio 

默认年轻代与老年代在堆结构的占比 默认 -XX:NewRatio = 2新生代占1,老年代占2,年轻代占整个堆的1/3;

                假如 -XX:NewRatio = 4新生代占1,老年代占4,年轻代占整个堆的1/5,NewRatio值就是设置老年代的占比,剩下的1给新生代;

设置新生代和老年代比例:
-Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:+UseSerialGC -XX:NewRatio=2 默认的

-Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:+UseSerialGC -XX:NewRatio=4
 def new generation   total 1856K, used 477K [0x00000000ff600000, 0x00000000ff800000, 0x00000000ff800000)
 tenured generation   total 8192K, used 431K [0x00000000ff800000, 0x0000000100000000, 0x0000000100000000

-XX:MaxTenuringThreshold=15

垃圾最大年龄不能超过15

强应用、软引用、弱引用、虚引用分别是什么?

                        

①强引用

    public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = obj1;
        obj1 = null;
        System.gc();
        System.out.println(obj1); //null
    }

 

②软引用

软引用:内存足够的前提下不收,内存不够时收;强引用:死了都不收;

 ③ 弱引用:不管内存是否够用, 只要有GC一定回收

 

 

public class WeekHashMapDemo {
    public static void main(String[] args) {
        myHashMap();
        System.out.println("===================");
        myWeekHashMap();

    }
    private static void myWeekHashMap() {
        WeakHashMap<Integer, String> weekHashMap = new WeakHashMap<>();

        Integer key = new Integer(2);
        String value = "weekHashMap";
        weekHashMap.put(key, value);
        System.out.println(weekHashMap); //{2=weekHashMap}

        key = null;
        System.out.println(weekHashMap); //{2=weekHashMap}

        System.gc();
        System.out.println(weekHashMap + "\t" + weekHashMap.size()); //{}    0
    }
    private static void myHashMap() {
        HashMap<Integer, String> hashMap = new HashMap<>();
        Integer key = new Integer(1); //这里的key指向的是一个Integer的引用
        String value = "HashMap";
        hashMap.put(key, value); //HashMap中的put放的是Node类型的K V键值对
        System.out.println(hashMap); //{1=HashMap}

        key = null; //key是否是null无所谓,跟HashMap没关系,Node的key的节点没有变化
        System.out.println(hashMap); //{1=HashMap}

        System.gc();
        System.out.println(hashMap + "\t" + hashMap.size()); //{1=HashMap} 1
    }
}

④ 虚引用:

 

引用队列

弱引用在GC时候会被装到引用队列中

public class PhantomReferenceDemo {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); //引用队列
        PhantomReference<Object> phantomReference = new PhantomReference<>(obj, referenceQueue);

        System.out.println(obj); //java.lang.Object@14ae5a5
        System.out.println(phantomReference.get()); //null,它的get方法总是返回null,无法访问对象的引用对象
        System.out.println(referenceQueue.poll()); //null

        System.out.println("==================");
        obj = null;
        System.gc();
        Thread.sleep(500);

        System.out.println(obj); //null
        System.out.println(phantomReference.get()); //null
        System.out.println(referenceQueue.poll()); //java.lang.ref.PhantomReference@7f31245a

    }
}

 

 

OOM:

java.lang.StackOverflowError
java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: Direct buffer memory
java.lang.OutOfMemoryError: unable to create new native thread
java.lang.OutOfMemoryError: Metaspace

                        

① 栈内存溢出:深度的方法调用 java.lang.StackOverflowError

public class StackOverFlowDemo {
    public static void main(String[] args) {
        stackOverFlowError();
    }

    public static void stackOverFlowError(){
        stackOverFlowError(); //Exception in thread "main" java.lang.StackOverflowError
    }
    /*
    这个叫错误,不是异常;
throwable是所有异常和错误的父类
java.lang.Object
    java.lang.Throwable
        java.lang.Error
            java.lang.VirtualMachineError
                java.lang.StackOverflowError

     */
}

 ② 堆内存溢出;对象太多了 Error   java.lang.OutOfMemoryError: Java heap space

public class JavaHeapSpaceErrorDemp {
    public static void main(String[] args) {
/*        String str = "kris";
        while (true){
            str += str + new Random().nextInt(11111111) + new Random().nextInt(2222222);
            str.intern();
        }*/
        byte[] bytes = new byte[90 * 1024 * 1024];//90M
        //Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    }
}

java.lang.OutOfMemoryError: GC overhead limit exceeded

JVM参数配置演示:-Xms10m -Xmx10m  -XX:MaxDirectMemorySize=5m

GC回收时间过长会抛出OutOfMemroyError;过长的定义是:超过98%的时间用来做GC并且回收了不到2%的堆内存;连续多次GC都只回收了不到2%的极端情况下才会抛出,假如不抛出GC overhead limit错误会发生什么情况呢?那就是GC清理的这么点内存很快会再次填满,迫使GC再次执行,这样就形成恶性循环,CPU使用率一直是100%,而GC却没有任何成果。

//-Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:MaxDirectMemorySize=5m 
public class GCOverHeadDemo {
    public static void main(String[] args) {
        int i = 0;
        List<String> list = new ArrayList<>();
        try {
            while (true){
                list.add(String.valueOf(++i).intern());
            }
        } catch (Throwable e) {
            System.out.println("***********i:" + i); // java.lang.OutOfMemoryError: GC overhead limit exceeded
            e.printStackTrace();  //***********i:145444
            throw e;
        }
    }
}

 

java.lang.OutOfMemoryError: Direct buffer memory

 配置参数: -Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:MaxDirectMemorySize=5m

导致原因:写NIO程序(非阻塞)经常使用ByteBuffer来读取或者写入数据,这是一种基于通道Channel与缓冲区Buffer的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的
DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在java堆和Native堆中来回复制数据。
ByteBuffer.allocate(capability)第一种方式是分配JVM堆内存,属于GC管辖范围,由于需要拷贝所以速度相对较慢;
ByteBuffer.allocate(capability)第二种方式是分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝所以速度相对较快;
但如果不断分配本地内存,堆内存很快使用,那么JVM就不需要执行GC,DirectByteBuffer对象们就不会被回收,这时候堆内存充足,但本地内存很快使用光了,再次尝试分配本地内存出出现
OutOfMemoryError,那么程序就直接崩溃了。

java\jre\lib\rt.jar(它会回去加载String、Object等,放到元空间保证java一开始就可以用)    rt.jar \sun\misc\VM.class

直接内存溢出:

public class DirectBufferMemoryDemo {
    //-Xms10m -Xmx10m -XX:+PrintGCDetails  -XX:MaxDirectMemorySize=5m
    public static void main(String[] args) {
        System.out.println("配置的maxDirectMemory" + (sun.misc.VM.maxDirectMemory() / (double)1024/ 1024 )+ "MB");
         try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
        //-XX:MaxDirectMemorySize=5m
         ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6* 1024 * 1024);
         // Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory

    }
}

高并发请求服务器时经常出现的异常:java.lang.OutOfMemoryError: unable to create new native
thread
准确的讲该native thread异常与对应的平台有关;

 导致原因:

①你的应用创建了太多线程,一个应用进程创建多个线程,超过系统承载极限;

②你的服务器并不允许你的应用程序创建这么多线程,linux系统默认允许创建的线程数是1024个,你的应用创建超过这个数量,就会报 java.lang.OutOfMemoryError: unable to create new native thread

解决办法:

①想办法降低你应用程序创建线程的数量,分析应用是否真的需要创建这么多线程,如果不是,改代码将线程数降到最低;

②对于有的应用,确实需要创建多线程,远超过linux系统的默认1024个线程的限制,可以通过修改linux服务器配置,扩大linux默认配置;

*************i = 4072
*************i = 4073
*************i = 4074
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
        at java.lang.Thread.start0(Native Method)
        at java.lang.Thread.start(Thread.java:717)
        at UnableCreateNewThreadDemo.main(UnableCreateNewThreadDemo.java:9)
 

 

 

create new native thread :①非root用户登录Linux系统测试; ②服务器级别调参调优;

 

 

[kris@hadoop101 ~]$ ulimit -u
4096

[kris@hadoop101 ~]$ vim /etc/security/limits.d/90-nproc.conf 
# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.

*          soft    nproc     4096
root       soft    nproc     unlimited

 

使用java -XX:+PrintFlagsInitial命令查看本机的初始化参数,-XX:MetaspaceSize为21810376B(大约为20.8M)
C:\Users\Administrator>java -XX:+PrintFlagsInitial
......
intx MaxTrivialSize                            = 6                                   {product}
     intx MaxVectorSize                             = 32                                  {C2 product}
    uintx MetaspaceSize                             = 21810376                            {pd product}
     bool MethodFlushing                            = true                                {product}
    uintx MinHeapDeltaBytes                         = 170392                              {product}
    uintx MinHeapFreeRatio                          = 40                                  {manageable}
     intx MinInliningThreshold                      = 250                                 {product}
     intx MinJumpTableSize                          = 10                                  {C2 pd product}
    uintx MinMetaspaceExpansion                     = 340784                              {product}
    uintx MinMetaspaceFreeRatio                     = 40                                  {product}
    uintx MinRAMFraction                            = 2                                   {product}

 

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

;import java.lang.reflect.Method;
//-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m
public class MetaspaceSizeOOMDemo {
    static class OOMTest{}
    public static void main(String[] args) {
        int i = 0;
        try {
            while (true) {
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMTest.class);
                enhancer.setUseCache(false);
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return methodProxy.invokeSuper(o, args);
                    }
                });
                enhancer.create();
            }
        }catch (Throwable e){
            System.out.println("**********多少次发生了异常: " + i);
            e.printStackTrace();
        }
            //**********多少次发生了异常: 282
        //java.lang.OutOfMemoryError: Metaspace

    }

}

 


 

转载于:https://www.cnblogs.com/shengyang17/p/10801453.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值