`

JVM总结

    博客分类:
  • java
jvm 
阅读更多

1.JVM内存模型

1.本地方法栈(Native)   调用c部分
2.程序计数器  (程序代码行数)  JVM支持多个线程同时运行,每个线程都有自己的程序计数器。倘若当前执行的是 JVM 的方法,则该寄存器中保存当前执行指令的地址;倘若执行的是native 方法,则PC寄存器中为空。
3.栈 stack :每个线程有一个私有的栈,随着线程的创建而创建。栈里面存着的是一种叫“栈帧”的东西,每个方法会创建一个栈帧,栈帧中存放了局部变量表(基本数据类型和对象引用)、操作数栈、方法出口等信息。栈的大小可以固定也可以动态扩展。当栈调用深度大于JVM所允许的范围,会抛出StackOverflowError的错误
4.堆  heap(存实际对象) 堆内存是 JVM 所有线程共享的部分,在虚拟机启动的时候就已经创建。所有的对象和数组都在堆上进行分配。这部分空间可通过 GC 进行回收。当申请不到空间时会抛出 OutOfMemoryError
5方法区  :主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。 关于方法区内存溢出的问题会在下文中详细探讨

2.ClassLoader双亲委派机制 可以保护jvm自己的安全

   双亲委派机制 : 一层一层的让父类去加载,如果顶层的加载器不能加载,然后再向下类推
 // BootStrap (最顶层) 01 java.lang.String rt.jar   /jdk/jre/lib/ 下面的jar
 // ExtClassLoader 02     /jdk/jre/lib/ext/下面的jar
  // AppClassLoader 03   //AppClassLoader
     // 双亲委派机制 可以保护java的核心类不会被自己定义的类所替代
<wiz_code_mirror>
 
 
 
 
 
1
// -XX:+TraceClassLoading
2
public static void main(String[] args) {
3
        Object o = new Object(); // jdk 自带的
4
        Demo01 demo01 = new Demo01();  // 实例化一个自己定义的对象
5
        // null 在这里并不代表没有,只是Java触及不到!Bootstrap
6
        System.out.println(o.getClass().getClassLoader()); // null
7
        System.out.println(demo01.getClass().getClassLoader()); // AppClassLoader
8
        System.out.println(demo01.getClass().getClassLoader().getParent()); // ExtClassLoader
9
        System.out.println(demo01.getClass().getClassLoader().getParent().getParent()); // null
10
    }
 
 
<wiz_code_mirror>
 
 
 
 
 
1
 // 思考:为什么我们刚才自己定义的 java.lang.String 没有生效?
2
 //Bootstrap 优先加载 没找到main方法  双亲委派机制 一层层加载
3
public class String {
4
    public static void main(String[] args) {
5
        System.out.println("hello");
6
    }
7
}
 
 
 
<wiz_code_mirror>
 
 
 
 
 
1
public class Demo01 {
2
    private static int m=0;
3
    public static void main(String[] args) {
4
        System.out.println(Parent.str);//没加会输出static init1 str如果加了final不会输出staticinit  没加final会先输出static init
5
        System.out.println(Parent2.str);
6
        Parent.kk();
7
    }
8
    static class Parent{
9
        public final static String str="hello";//会优先放常量池
10
        static  {
11
            System.out.println("static init1");
12
        }
13

14
        public static void kk() {
15
            m++;
16
            System.out.println(m);
17
            kk();
18
        }
19
    }
20
    static class Parent2{
21
        public static final String str=UUID.randomUUID().toString();//会输出静态代码块内容
22
        static  {
23
            System.out.println("static init2");
24
        }
25
    }
26
}
 
 

3.JDK1.8之后和1.7区别

JDK1.7之前 
永久代:用于存储一些虚拟机加载类信息,常量,字符串、静态变量等等。。。。这些东西都会放到永久代中; 
永久代大小空间是有限的:如果满了 OutOfMemoryError:PermGen 
JDK1.8之后 
彻底将永久代移除 HotSpot jvm ,Java Heap 中或者 Metaspcace(Native Heap)元空间; 
元空间就是方法区在 HotSpot jvm 的实现; 
方法区重要就是来存:类信息,常量,字符串、静态变量、符号引用、方法代码。。。。。。 
元空间和永久代,都是对JVM规范中方法区的实现。 
元空间和永久代最大的区别:==元空间并不在Java虚拟机中,使用的是本地内存!== 
-XX:MetasapceSize10m 
 

4.方法区渊源

Method Area 方法区 是 Java虚拟机规范中定义的运行是数据区域之一,和堆(heap)一样可以在线程之间共享!栈不能共享

天上飞的理念都会有落地的实现!

JDK1.7之前

永久代:用于存储一些虚拟机加载类信息,常量,字符串、静态变量等等。。。。这些东西都会放到永久代中;

永久代大小空间是有限的:如果满了 OutOfMemoryError:PermGen

JDK1.8之后

彻底将永久代移除 HotSpot jvm ,Java Heap 中或者 Metaspcace(Native Heap)元空间;

元空间就是方法区在 HotSpot jvm 的实现;

方法区重要就是来存:类信息,常量,字符串、静态变量、符号引用、方法代码。。。。。。

元空间和永久代,都是对JVM规范中方法区的实现。

元空间和永久代最大的区别:==元空间并不在Java虚拟机中,使用的是本地内存!==

-XX:MetasapceSize10m

5.堆内存和GC过程

Java7之前: 
Heap 堆,一个JVM实例中只存在一个堆,堆的内存大小是可以调节的。 
可以存的内容:类、方法、常量、保存了类型引用的真实信息; 
分为三个部分: 
新生区:Young (Eden-s0-s1)  Eden-s0-s1默认8:1:1
养老区:Old Tenure   大对象(-XX:PretenureSizeThreadshold=1024)直接进入老年代,在新生代里面长期存活的对象进入老年代。老年代对应的是major gc。
新生区和养老区默认1:2
永久区:Perm 
堆内存在==逻辑上==分为三个部分:新生、养老、永久(JDK1.8以后,叫元空间) 
物理上只有 新生、养老;元空间在本地内存中,不在JVM中! 
GC 垃圾回收主要是在 新生区和养老区,又分为 普通的GC 和 Full GC,如果堆满了,就会爆出 OutOfMemory; 
新生区 
新生区 就是一个类诞生、成长、消亡的地方! 
新生区细分: Eden、s(from to),所有的类Eden被 new 出来的,慢慢的当 Eden 满了,程序还需要创建对象的时候,就会触发一次轻量级GC;清理完一次垃圾之后,会将活下来的对象,会放入幸存者区(),....... 清理了 20次之后,出现了一些极其顽强的对象,有些对象突破了15次的垃圾回收!这时候就会将这个对象送入养老区!运行了几个月之后,养老区满了,就会触发一次 Full GC;假设项目1年后,整个空间彻彻底底的满了,突然有一天系统 OOM,排除OOM问题,或者重启; 
Sun HotSpot 虚拟机中,内存管理(分代管理机制:不同的区域使用不同的算法!) 
Eden from to 
99% 的对象在 Eden 都是临时对象; 
养老区 
15次都幸存下来的对象进入养老区,养老区满了之后,触发 Full GC 
默认是15次,可以修改! 
永久区(Perm) 
放一些 JDK 自身携带的 Class、Interface的元数据; 
几乎不会被垃圾回收的; 
OutOfMemoryError:PermGen 在项目启动的时候永久代不够用了?加载大量的第三方包! 
JDK1.6之前: 有永久代、常量池在方法区; 
JDK1.7:有永久代、但是开始尝试去永久代,常量池在堆中; 
JDK1.8 之后:永久代没有了,取而代之的是元空间;常量池在元空间中; 
闲聊:方法区和堆一样,是共享的区域,是JVM 规范中的一个逻辑的部分,但是记住它的别名 非堆 
元空间:它是本地内存! 

6.堆内存调优和常用参数(初识)

1.8之后permSize和MaxPermSize被-XX:MetaspaceSize和-XX:MaxMetaspaceSize取代
-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
 -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
 

-XX:+PrintGCDetails:输出详细的GC处理日志

-XX:+PrintGCTimeStamps:输出GC的时间戳信息

-XX:+PrintGCDateStamps:输出GC的时间戳信息(以日期的形式)

-XX:+PrintHeapAtGC:在GC进行处理的前后打印堆内存信息

-Xloggc:(SavePath):设置日志信息保存文件

Minor GC ,Full GC 触发条件

Minor GC触发条件:当Eden区满时,触发Minor GC。

Full GC触发条件:

(1)调用System.gc时,系统建议执行Full GC,但是不必然执行

(2)老年代空间不足

(3)方法去空间不足

(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存

(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

Java堆:所有线程共享。虚拟机启动时创建。存放对象实力和数组。所占内存最大。分为新生代(Young区),老年代(Old区)。新生代分Eden区,Servior区。Servior区又分为From space区和To Space区。Eden区和Servior区的内存比为8:1。 当扩展内存大于可用内存,抛OOM。

 

GC流程  ,对象如何晋升到老年代

对象优先在新生代区中分配,若没有足够空间,Minor GC; 大对象(需要大量连续内存空间)直接进入老年态;长期存活的对象进入老年态。如果对象在新生代出生并经过第一次MGC后仍然存活,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。

 

  1. 【对象优先在Eden中分配,当Eden中没有足够的空间分配时会促发一次Minor GC。每次Minor GC结束后,Eden区会清空,因为它会把Eden中还依然存活的对象放到Survivor中,当Survivor中放不下时,则由分派担保进入老年代中。
  2. 大对象直接进入老年代中。-XX:+PretenuerSizeThreshold 控制”大对象的“的大小。即当创建的对象大于这个临界值时,则该对象直接进入老年代。
  3. 长期存活的对象将进入老年代。虚拟机对每个对象定义了一个对象年龄(Age)计数器。当年龄增加到一定的临界值时,就会晋升到老年代中,该临界值由参数:-XX:MaxTenuringThreshold来设置。如果对象在Eden出生并在第一次发生Minor GC时仍然存活,并且能够被Survivor中所容纳的话,则该对象会被移动到Survivor中,并且设Age=1;以后每经历一次Minor GC,该对象还存活的话会被移动到另一个Survivor区中,并且Age=Age+1。
  4. 动态对象年龄判定:如上所示,虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升到老年代,如果在Survivor区中相同年龄(设年龄为age)的对象的所有大小之和超过Survivor空间的一半,年龄大于或等于该年龄(age)的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。】
老年代的垃圾回收称作Full GC。老年代所占用的内存大小为-Xmx对应的值减去-Xmn对应的值。
<wiz_code_mirror>
 
 
 
 
 
1
/**
2
 * 默认情况:
3
 * maxMemory : 1808.0MB (虚拟机试图使用的最大的内存量  一般是物理内存的 1/4)
4
 * totalMemory : 123.0MB (虚拟机试图默认的内存总量 一般是物理内存的 1/64)
5
 */
6
// 我们可以自定堆内存的总量
7
// -XX:+PrintGCDetails; // 输出详细的垃圾回收信息
8
// -Xmx: 最大分配内存; 1/4
9
// -Xms: 初始分配的内存大小; 1/64
10

11
// -Xmx1024m -Xms1024m -XX:+PrintGCDetails
12
public class Demo01 {
13
    public static void main(String[] args) {
14
        // 获取堆内存的初始大小和最大大小
15
        long maxMemory = Runtime.getRuntime().maxMemory();
16
        long totalMemory = Runtime.getRuntime().totalMemory();
17

18
        System.out.println("maxMemory="+maxMemory+"(字节)、"+(maxMemory/1024/(double)1024)+"MB");
19
        System.out.println("totalMemory="+totalMemory+"(字节)、"+(totalMemory/1024/(double)1024)+"MB");
20

21
    }
22
}
 
 
 
<wiz_code_mirror>
 
 
 
 
 
1
/*
2
 * -Xmx8m -Xms8m -XX:+PrintGCDetails
3
 *
4
 * 分析GC日志:
5
 *
6
 *  [Times: user=0.00 sys=0.00, real=0.00 secs]
7
 * 1、GC 类型  GC:普通的GC,Full GC :重GC
8
 * 2、1536K 执行 GC之前的大小
9
 * 3、504K  执行 GC之后的大小
10
 * 4、(2048K) young 的total大小
11
 * 5、0.0012643 secs 清理的时间
12
 * 6、user 总计GC所占用CPU的时间   sys OS调用等待的时间   real 应用暂停的时间
13
 *
14
 * GC :串行执行 STW(Stop The World)  并行执行   G1
15
*/
16

17
public class Demo02 {
18
    public static void main(String[] args) {
19
        System.gc(); // 手动唤醒GC(),等待cpu的调用
20
        String str = "ilovecoding";
21
        while (true){
22
            str += str
23
                    + new Random().nextInt(999999999)
24
                    + new Random().nextInt(999999999);
25
        }
26
        // 出现问题:java.lang.OutOfMemoryError: Java heap space
27
    }
28
}
 
 

GCDump分析内存泄露分析

安装JProfile
运行时加上参数:-XX:+HeapDumpOnOutOfMemoryError   生成的文件在项目根目录下/同级
分享到:
评论

相关推荐

    jvm总结.rtf

    jvm总结.rtf

    精简版JVM总结.pdf

    Java虚拟机(JVM)是Java程序运行的核心,它的内存管理是优化程序性能的关键。本文主要探讨了JVM的内存区域、线程私有部分、内存溢出异常、垃圾回收机制及其重要性。 首先,JVM内存区域可以分为五个主要部分: 1. ...

    JVM知识点总结的思维导图

    JVM总结

    JVM总结.docx

    Java虚拟机(JVM)是Java程序运行的基础,它的核心组成部分之一就是垃圾收集器(Garbage Collector, GC)。GC的主要任务是自动管理程序中的内存,回收不再使用的对象,避免内存泄漏,确保系统的稳定运行。HotSpot ...

    JVM调优总结

    1.1 JVM调优总结-序3 1.2 JVM调优总结(一)-- 一些概念 4 1.3 JVM调优总结(二)-一些概念 7 1.4 JVM调优总结(三)-基本垃圾回收算法 9 1.5 JVM调优总结(四)-垃圾回收面临的问题 12 1.6 JVM调优总结(五)-分代...

    个人对JVM总结图.png

    个人对JVM的总结图。包括JVM的五部分(Program Counter Register、JVM Stack、Native Method Stack、heap、method area)。欢迎各位网友指正错误,互相学习讨论

    jvm总结整理.pptx

    JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

    JVM调优总结.pdf

    本文档总结了JVM调优的基础知识和一些核心概念,旨在帮助开发者更好地掌握Java程序的性能优化。 首先,文档提到了Java中的数据类型分为基本类型和引用类型。基本类型的变量存储的是原始数据值,而引用类型的变量...

    JVM调优总结 JVM调优总结

    ### JVM调优总结 #### 一、概述 Java虚拟机(JVM)是Java程序的核心运行环境,对于提高Java应用程序性能至关重要。JVM调优是指通过调整JVM的配置参数来优化程序性能的过程。本文将围绕JVM调优展开讨论,重点分析数据...

    JVM性能调优总结.docx

    JVM性能调优总结 JVM性能调优是Java开发中非常重要的一方面,直接影响到系统的性能和稳定性。本文将总结JVM性能调优的经验和技巧,并提供一些实用的配置参数和建议。 一、堆大小设置 堆大小是JVM性能调优中的一个...

    jvm干货总结图

    jvm干货总结图

    JVM调优总结 -Xms -Xmx -Xmn -Xss

    JVM调优总结 -Xms -Xmx -Xmn -Xss JVM 调优是 Java virtual machine 的性能优化,通过调整 JVM 的参数来提高 Java 应用程序的性能。其中,-Xms、-Xmx、-Xmn、-Xss 是四个重要的参数,分别控制 JVM 的初始堆大小、...

    jvm自己学习总结

    jvm自己学习总结,对JVM的工作原理进行记录学习笔记

    JVM调优总结PDF,带原理图

    ### JVM调优与垃圾回收机制详解 #### 一、引言 随着软件系统的复杂度不断提高,性能优化成为了软件开发中的一个重要环节。对于Java应用程序来说,Java虚拟机(JVM)的性能直接影响着应用的整体表现。垃圾回收(GC)...

    jvm的基础知识总结

    JVM的基础知识涵盖了其内存模型、垃圾回收机制、线程模型等多个方面,下面将详细总结这些基础知识。 ### JVM内存模型 JVM内存模型主要可以分为线程共享区域和线程私有区域。 **线程共享区域** 1. 堆(Heap):...

    JVM调优与内存管理总结

    Java虚拟机(JVM)调优与内存管理是优化Java应用程序性能的关键环节。JVM内存主要分为新生代、老年代和持久代,每个区域都有其特定的垃圾回收策略。 1. 引用计数法(Reference Counting):这是一种简单的垃圾回收...

    java与jvm知识总结

    Java与JVM(Java虚拟机)是Java编程语言的核心组成部分,它们之间紧密相连,共同构成了Java应用程序的运行环境。理解这两个概念对于Java开发者至关重要。本文将深入探讨Java类加载机制以及JVM的工作原理。 首先,让...

    面试总结-JVM .png

    JVM 的运行机制 多线程 JVM 的内存区域 JVM 会创建操作系统的接口创建一个原生线程。JVM 线程和操作系统线程是一一对应的

    JVM调优总结1-12.docx

    JVM调优总结 JVM(Java Virtual Machine)是 Java 语言的运行环境,负责将 Java 字节码转换为机器码并执行。然而,随着 Java 应用程序的复杂度和规模的增加,JVM 的性能变得越来越重要。因此,JVM 调优是非常必要的...

Global site tag (gtag.js) - Google Analytics