JVM知识点大杂烩

JVM知识点

概况: 本文总结一些JVM杂乱的知识点,以供参考

1.JVM内存结构

1.1 java虚拟机运行时数据区图


1.1.1 虚拟机栈(VM Stack)

调用一个方法会启用(创建)一个栈帧

栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

java虚拟机栈

每个方法在执行的时候会创建一个栈帧(Stack Fram)

java栈是一块线程私有的内存空间,一个栈,一般由三部分组成:局部变量表,操作数栈和帧数据区

选项描述
局部变量表用于报错函数的参数局部变量
操作数据栈主要保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间
帧数据区除了局部变量表和操作数栈以外,栈还需要一些数据来支持常量池的解析,这里帧数据保存着访问常量池的指针,方便程序访问常量池,另外,当函数返回或者出现异常时,虚拟机必须有一个异常处理表,方便发送异常的时候找到异常的代码。因此,异常处理表也是帧数据区的一部分

1.1.2 本地方法栈(Native Method Stack)

线程私有 ,是属于底层,调用C语言、汇编等, 无法做调优。


1.1.3 堆(heap)

内存最大的一块,一般也是针对这块进行调优

堆描述
几乎所有的对象都存放在堆中,且堆是自动化管理,通过垃圾回收机制,垃圾对象会自动清理,不需要手动释放
根据垃圾回收机制不同,Java堆有可能有不同的结构,最为常见的就是将整个java堆分为新生代老年代。 其中新生代存放新生的对象或者年龄不大的对象,老年代则存放老年对象
新生代分为eden区,s0区,s1区,s0和s1也被称为 fromto区域。他们两块是大小相等,并且可以互换角色的空间

补充: s0 和 s1 采用复制(copy)垃圾回收算法

from和to区来回切换身份.png

绝大多数情况下,对象首先分配在eden区,在一次新生代回收后,如果对象还存活,则会进入s0
或者s1区,之后每经过一次新生代回收,如果对象存活则它的年龄就+1. 默认达到15则进入老年代。


1.1.4 方法区(Mehtod Area)

所有线程共享 ,用于存放已被虚拟机加载的类信息常量静态变量即时编译器编译后的代码等数据

大小决定了系统可以保存多少个类。 方法区可以理解为永久区(perm)

JDK1.6/1.7可以理解为permgen space (永久驻留区),里面还包括一些运行时的常量池信息,
字符串字面值. JDK1.8开始已经没有这个概念,1.8称为元空间其大小只受物理内存限制

1.1.5 直接内存
  • Java的NIO允许Java程序使用直接内存
  • 直接内存是在Java堆外的、直接向系统申请的内存区间
  • 通常,访问直接内存的速度优于Java堆。
  • 因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。
  • 由于直接内存在Java堆外,因此它的大小不会受限于Xmx指定的最大堆大小
  • 但是系统内存是有限的,Java堆和直接内
  • 存的总和依然受限于操作系统能给出的最大内存
名称描述
解决的是数据存储的问题,即数据怎么放,放在哪儿
解决程序运行问题,即程序如何执行,或者如何处理数据
方法区是辅助堆栈的一块永久区(Perm),解决堆栈信息的产生,是先决条件

直接内存,一般不用设置。JVM自动优化。


2 如何确认为垃圾

什么是垃圾


2.1 引用计数

有一个引用,计数就添加1, 但是: 会有循环引用问题


2.2 正向可达(现在JVM使用的算法)

从roots对象(GC Roots 根对象)计算可达的对象。


3 垃圾收集算法

3.1 Mark-Sweep 标记清除

标记清除法


3.2 Copying 复制

复制算法

copy效率还算高,但是当对象存活率较高时要进行较多复制操作,效率也会变低。


3.3 Mark-Compact 标记压缩/标记整理算法

标记整理算法


3.4 JVM采用分代算法

JVM采用分代算法


4 JVM 参数

4.1 参入介绍

 -   标准参数,所有JVM都支持

 -X  非标准,每个JVM实现不尽相同

 -XX 不稳定,下个版本可能取消
-XX : 属于系统级别(JVM)的配置。例如 GC日志信息,使用垃圾回收器

非 -XX 基本属于应用层面的配置。如分配堆、栈的大小等。

+ 启用

- 禁用

4.2 JVM常见参数

#堆设置 
-Xms:初始堆大小 ,设置java启动时初始堆大小
-Xmx:最大堆大小 
-XX:NewSize=n:设置年轻代大小 
-XX:NewRatio=n:设置年轻代和年老代的比值.如:3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4 
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值.注意Survivor区有两个.如:3,表示Eden:Survivor=3:2,
                    一个Survivor区占整个年轻代的1/5 
-XX:MaxPermSize=n:设置持久代大小 

#收集器设置 
-XX:+UseSerialGC:设置串行收集器 
-XX:+UseParallelGC:设置并行收集器 
-XX:+UseParalledlOldGC:设置并行年老代收集器 
-XX:+UseConcMarkSweepGC:设置并发收集器 

#垃圾回收统计信息 
-XX:+PrintGC  使用这个参数,虚拟机启动后,只要遇到GC就会打印日志
-XX:+PrintGCDetails 可以查看信息信息,包括各个区的情况
-XX:+PrintGCTimeStamps 
-Xloggc:filename 
-XX:+PrintCommandLineFlags:可以将隐式或者显示传给虚拟机的参数输出。

通过实验练习,不必死记硬背,重在理解,使用时查询即可

更加全面的参数介绍可查看官网


4.2 常用虚拟机

  • openJDK
  • HotSpot (JDK1.8 默认模式为 Server模式)

5.垃圾收集器

不同的垃圾收集器可以采用不同的垃圾回收算法


5.1 Serial 收集器

是一个单线程的收集器,但是不能利用多处理器,吞吐量也不是很高(up to approximately 100M)

指定参数:

-XX:+UseSerialGC

5.2 The paralle collector 并行收集器

垃圾收集效率较高吞吐量也高处理线程进程较多


5.3 The Mostly Concurrent Collectors 并发收集器

并发量大


5.3.1 CMS collector

使用时指定参数 -XX:+UseconcMarkSweepGC

优点: 停顿时间短

5.3.2 G1 collector

参数指定-XX:+UseG1GC

停顿时间短,但是并发量也大。java9推荐使用


5.4 小结:如果选择垃圾回收器

无监控不调优,根据监控来选择, 根据业务场景来进行选择。


6.对象的分配

虚拟机自动调整分配


6.1 栈上分配

6.1.1 特征
  • 线程私有小对象
  • 无逃逸
  • 支持标量替换
  • 无需调整优化,使用JVM默认即可。

    方法结束,则栈帧消失,所以方法中new出来的对象,在其他地方有引用(逃逸了),就不能在栈上分配


6.1.1.1 逃逸行为
  • 逃逸行为在栈上(方法中)分配的对象,在方法销毁的时候对象没有在方法栈中被销毁,而被其他全局变量引用,导致对象不能被回收
  • jvm进行优化的时候在栈上分配的对象是不能存在逃逸行为的,

逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,称为方法逃逸。甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸

逃逸有两种情况:

情况描述
方法逃逸当一个对象在方法中定义之后,作为参数传递到其它方法中
线程逃逸如类变量或实例变量,可能被其它线程访问到

6.1.1.2 同步消除

线程同步本身比较耗,如果确定一个对象不会逃逸出线程,无法被其它线程访问到,那该对象的读写就不会存在竞争,则可以消除对该对象的同步锁,通过-XX:+EliminateLocks可以开启同步消除

6.1.1.3 标量替换
  • 标量是指不可分割的量,如java中基本数据类型和reference类型,相对的一个数据可以继续分解,称为聚合量
  • 如果把一个对象拆散,将其成员变量恢复到基本类型来访问就叫做标量替换
  • 如果逃逸分析发现一个对象不会被外部访问,并且该对象可以被拆散,那么经过优化之后,并不直接生成该对象,而是在栈上创建若干个成员变量;

通过-XX:+EliminateAllocations可以开启标量替换,-XX:+PrintEliminateAllocations查看标量替换情况。


6.1.2 过程解读
  • 如果java虚拟机开了栈上分配,则首先会进行栈上分配,如果栈上分配不了,则进入线程本地分配,
    然后查看自己是否是一个对象,是否去老年代分配,如果不是特别大,则去eden区。

  • 如果一个对象特别小,且开了栈上分配的优化,默认是开着的。
    好处,放在栈上(栈帧),方法结束或者线程结束,则自动回收,都不用使用垃圾回收。

  • 栈空间分配满了,则去找线程本地分配每一个线程执行的时候都会给自己分配一部分专用内存
    即线程本地内存。在eden中申请,默认 1%。

  • 为什么会申请一个线程本地的区域呢?如果所有的线程new出来的对象都放在eden区,则eden则必须要加锁
    如果每个线程都一个自己独立的区域(同时也算大),则eden就不用再加锁。这样就提高对象分配效率


6.2 线程本地分配TLAB(Thread Local ALLacation Buffer)

特征:
1. 占用eden,默认1%
2. 多线程时不用竞争eden即可申请空间,提高效率
3. 小对象
4. 无需调整优化,使用JVM默认即可。


7 虚拟机参数

JVM分配参数相关

-XX:+DoEscapeAnalysis 开启逃逸分析,

-XX:-DoEscapeAnalysis 关闭逃逸分析,对象就不能分配在栈上默认情况下是开启逃逸分析的

-XX:+EliminateAllocations可以开启标量替换,
-XX:-EliminateAllocations 关闭

-XX:-UseTLAB  关闭线程本地内存
-XX:+UseTLAB  开启线程本地内存

8 代码解析

8.1 案例一

不是栈上分配,不使用线程本地分配,直接在eden分配。

(一)源码

-XX:-DoEscapeAnalysis -XX:-EliminateAllocations  -XX:-UseTLAB -XX:+PrintGC
public class Test1 {

    public static class User{
        private int i ;
        private String name;        
        public User(int i, String name){
            this.i = i;
            this.name = name;
        }

    }
      public static void alloc(int i){
          new User(i,"name"+i);
      }
      public static void main(String [] args){
          long b = System.currentTimeMillis();
          for(int i=0;i<1000000000;i++){
              alloc(i);
          }
          long e = System.currentTimeMillis();
          System.out.println("消耗时间为:" + (e - b));

      }

}

(二)设置参数
java虚拟机性虚拟参数调优测试

(三)GC打印分析

[GC (Allocation Failure)  33279K->624K(125952K), 0.0034251 secs]
[GC (Allocation Failure)  33904K->632K(125952K), 0.0009171 secs]
[GC (Allocation Failure)  33912K->640K(125952K), 0.0006934 secs]
[GC (Allocation Failure)  33920K->648K(159232K), 0.0008063 secs]
[GC (Allocation Failure)  67208K->648K(159232K), 0.0018330 secs]
[GC (Allocation Failure)  67208K->632K(221696K), 0.0007944 secs]
[GC (Allocation Failure)  133752K->616K(221696K), 0.0012878 secs]
[GC (Allocation Failure)  133736K->648K(354816K), 0.0005041 secs]
[GC (Allocation Failure)  266888K->616K(354816K), 0.0013638 secs]
消耗时间为:733

描述:GC 第一次从 33279K –> 624K。


8.2 案例二

使用线程本地分配

(一)参数

-XX:-DoEscapeAnalysis -XX:-EliminateAllocations  -XX:+UseTLAB -XX:+PrintGC

(二)设置并运行

使用线程本地分配

(三)运行结果分析

使用以后耗时变短。使用本地线程分配时,不用在eden分配对象时进行加锁,提高分配效率。


8.3 案例三

使用栈上分配
(一)参数

-XX:+DoEscapeAnalysis -XX:+EliminateAllocations  -XX:+UseTLAB -XX:+PrintGC

(二)设置并运行
使用栈分配

(三)结果分析

使用栈分配后耗时明显变短


8.4 案例四

打印GC的细节

-XX:+PrintGCDetails

(一)源码

public class Test02 {

     public static void main(String[] args) {

        byte[] b= new byte[1024];
    }

}

(二)参数

-XX:-DoEscapeAnalysis -XX:+EliminateAllocations  -XX:+PrintGCDetails

(三)设置并运行
PrintGCDetails

(四)结果分析

Heap
 PSYoungGen      total 38400K, used 2662K [0x00000000d5e00000, 0x00000000d8880000, 0x0000000100000000)
  eden space 33280K, 8% used [0x00000000d5e00000,0x00000000d6099b20,0x00000000d7e80000)
  from space 5120K, 0% used [0x00000000d8380000,0x00000000d8380000,0x00000000d8880000)
  to   space 5120K, 0% used [0x00000000d7e80000,0x00000000d7e80000,0x00000000d8380000)
 ParOldGen       total 87552K, used 0K [0x0000000081a00000, 0x0000000086f80000, 0x00000000d5e00000)
  object space 87552K, 0% used [0x0000000081a00000,0x0000000081a00000,0x0000000086f80000)
 Metaspace       used 2591K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 288K, capacity 386K, committed 512K, reserved 1048576K

PrintGCDetails实验1


8.5 案例五

不使用线程本地缓存分配

(一)参数

-XX:-DoEscapeAnalysis -XX:-EliminateAllocations  -XX:-UseTLAB -XX:+PrintGCDetails

(二)运行过程

不适用线程本地分配


8.6 案例六

使用Runtime 等java API大致估算使用内存情况

(一)源码

public class Test3 {

    public static void main(String[] args) {

        printMemoryInfo();

        byte[] b = new byte[1024*1024];

        System.out.println("---------");
        printMemoryInfo();

    }

    public static void printMemoryInfo() {
        System.out.println("total:" + Runtime.getRuntime().totalMemory());
        System.out.println("free:" + Runtime.getRuntime().freeMemory());
    }
}

(二)打印情况

total:128974848
free:126930104
---------
total:128974848
free:125881512

(三)分析结果

其中free部分内存差不多使用了1M(1024*1024)


8.7 案例七

内存溢出

-Xms10 程序起始的时候为其分配多少内存

-Xmx10M 最大内存分配多少

一般起始值要小于最大值。如果是调优则可设置相等或接近。

(一)参数


-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/Test04.dump -Xms10M -Xmx10M -XX:+PrintGCDetails

(二)工具
使用visualVM 打开Test04.dump 这个文件。使用VM coredumps功能进行分析

下载安装这个软件. 地址

注意:在JDK中的bin目录下也有一个jvisualvm.exe

步骤:

  • 【File】 -> 【load】
  • 加载文件

visualVM选择文件类型.png

  • 加载文件并分析

内存溢出图形分析.png

  • 通过分析可以看出byte数组占比很高。这个时候就可以检查byte数组相关的地方。
  • 找出地方,然后进行修正即可。

可以参考官网visualVM文档


8.8 案例8

线程栈大小

(一)源码

package com.jvm;

/**
 * 递归调用,没有让递归结束。每个方法调用都会创建一个栈帧。
 * 所以栈空间一定会溢出
 *
 */
public class Test5 {

    static int count = 0;

    static void r() {
        count ++ ;
        r();
    }
    public static void main(String[] args) {

        try {
            r();
        } catch (Throwable t) {
            System.out.println(count); //stackOverFlow
        }
    }
}

(二)JVM 参数调整

 -Xss128k

(三)打印结果
栈溢出问题.png

通过调整不同Xss 大小。来设置递归的次数。


8.9 案例九

(一)参数

-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags

-XX:+PrintCommandLineFlags 会将JVM输入的参数打印出来。

(二)源码

public class Test01 {

    public static void main(String[] args) {

        //-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags

        //查看GC信息
        System.out.println("max memory:" + Runtime.getRuntime().maxMemory());
        System.out.println("free memory:" + Runtime.getRuntime().freeMemory());
        System.out.println("total memory:" + Runtime.getRuntime().totalMemory());

        byte[] b1 = new byte[1*1024*1024];
        System.out.println("分配了1M");
        System.out.println("max memory:" + Runtime.getRuntime().maxMemory());
        System.out.println("free memory:" + Runtime.getRuntime().freeMemory());
        System.out.println("total memory:" + Runtime.getRuntime().totalMemory());

        byte[] b2 = new byte[4*1024*1024];
        System.out.println("分配了4M");
        System.out.println("max memory:" + Runtime.getRuntime().maxMemory());
        System.out.println("free memory:" + Runtime.getRuntime().freeMemory());
        System.out.println("total memory:" + Runtime.getRuntime().totalMemory());

    }

}

(三)结果输出

-XX:InitialHeapSize=5242880 -XX:MaxHeapSize=20971520 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseSerialGC 
max memory:20316160
free memory:5312688
total memory:6094848
[GC (Allocation Failure) [DefNew: 763K->192K(1856K), 0.0018667 secs] 763K->528K(5952K), 0.0019340 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
分配了1M
max memory:20316160
free memory:4471136
total memory:6094848
[GC (Allocation Failure) [DefNew: 1249K->0K(1856K), 0.0017924 secs][Tenured: 1552K->1552K(4096K), 0.0027280 secs] 1585K->1552K(5952K), [Metaspace: 2587K->2587K(1056768K)], 0.0046291 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
分配了4M
max memory:20316160
free memory:4539496
total memory:10358784
Heap
 def new generation   total 1920K, used 69K [0x00000000fec00000, 0x00000000fee10000, 0x00000000ff2a0000)
  eden space 1728K,   4% used [0x00000000fec00000, 0x00000000fec115b8, 0x00000000fedb0000)
  from space 192K,   0% used [0x00000000fedb0000, 0x00000000fedb0000, 0x00000000fede0000)
  to   space 192K,   0% used [0x00000000fede0000, 0x00000000fede0000, 0x00000000fee10000)
 tenured generation   total 8196K, used 5648K [0x00000000ff2a0000, 0x00000000ffaa1000, 0x0000000100000000)
   the space 8196K,  68% used [0x00000000ff2a0000, 0x00000000ff824190, 0x00000000ff824200, 0x00000000ffaa1000)
 Metaspace       used 2594K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 288K, capacity 386K, committed 512K, reserved 1048576K

(四)分析

总结:

  • 在实际工作中,通常直接将初始堆的大小最大堆的大小设置相等。
  • 这样的好处是可以减少程序运行时的垃圾回收次数,从而提高性能。
  • 如何Tomcat调优的时候,可以这么操作。尽量调节大小相等

解释: 当分配给初始值比较小时,当内存不够且没有达到最大值时,会不断的申请内存。


8.10 案例十

新生代的配置:-Xmn: 可以设置新生代的大小,设置一个比较大的新生代会减少老年代,这个参数对系统性能以及GC行为有很多影响,新生代大小一般会设置整个堆空间的 1/3 到 1/4左右。

-XX:SurvivorRatio: 用来设置新生代中eden空间和from/to空间的比例。
含义-XX:SurvivorRation = eden/from = eden/to.(from = to 大小一致)

(一)源码

public class Test02 {

    public static void main(String[] args) {

        //第一次配置
        //-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC

        //第二次配置
        //-Xms20m -Xmx20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC

        //第三次配置
        //-XX:NewRatio=老年代/新生代
        //-Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC

        byte[] b = null;
        //连续向系统申请10MB空间
        for(int i = 0 ; i <10; i ++){
            b = new byte[1*1024*1024];
        }
    }
}

(二)分析

老年代设置占堆比例较大是应该的,很多大对象,以及其他从新生代跑过来的对象在此,做一个应用程序的支撑。如果新生代设置太小,则内存不够以后,会转向老年代

老年代产生GC, 引起Full GC,这样会影响性能。


(三) 小节
6. 总结

描述
不同的堆分布情况,对系统执行会产生一定的影响,在实际工作中,应该根据系统的特点做出合理的配置,基本策略:尽可能将对象预留在新生代,减少老年代的GC次数
除了可以设置新生代的绝对大小(-Xmn),还可以使用(-XX:NewRatio)来设置新生代和老年代的比例:-XX:NewRation = 老年代/新生

8.11 案例十一

java虚拟机提供了参数 -Xss来指定线程的最大栈空间,整个参数也直接决定了函数可调用的最大深度

(一) 参数

-Xss1m  

(二) 源码

public class Test04 {
    //栈调用深度
    private static int count;

    public static void recursion(){
        count++;
        recursion();
    }
    public static void main(String[] args){
        try {
            recursion();
        } catch (Throwable t) {
            System.out.println("调用最大深入:" + count);
            t.printStackTrace();
        }
    }
}

8.12 案例十二

在java程序的运行过程中,如果堆空间不足,则会抛出内存溢出的错误(Out of Memory) OOM一旦发生在生产环境上,可能引起业务中断。java虚拟机提供了 -XX:+HeapDumpOnOutOfMemoryError 使用该参数可以在内存溢出时导出整个堆信息,与之配合使用的还有参数-XX:HeapDumpPath,可以设置导出堆的存放路径

内存分析工具: Memory Analyzer 1.5.0 (是Eclipse中的插件,与Eclipse集成)
地址:http://download.eclipse.org/mat/1.5/update-site/

(一)参数

-Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/Test03.dump

(二)源码

public class Test03 {

    public static void main(String[] args) {

        //-Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/Test03.dump
        //堆内存溢出
        Vector v = new Vector();
        for(int i=0; i < 5; i ++){
            v.add(new Byte[1*1024*1024]);
        }

    }
}

(三)结果

java.lang.OutOfMemoryError: Java heap space
Dumping heap to d:/Test03.dump ...
Heap dump file created [1215404 bytes in 0.017 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.base.Test03.main(Test03.java:10)

9 Tomcat 优化配置

9.1 常用参数


CATALINA_OPTS="
-server 
-Xms4g 
-Xmx4g
-Xss512k 
-XX:+AggressiveOpts    //表示虚拟机能用上的优化全启用。
-XX:+UseBiasedLocking  //锁优化
-XX:PermSize=64M      //永久区。1.8取消了
-XX:MaxPermSize=256M  //最大永久区大小
-XX:+DisableExplicitGC //在 程序代码中不允许有显示的调用“System.gc()”。每次在到操作结束时手动调用 System.gc() 一下,付出的代价就是系统响应时间严重降低,就和关于 Xms,Xmx 里的解释的原理一样,这样去调用 GC 导致系统的 JVM 大起大落。

9.2 更细的参数


 -XX:+UseConcMarkSweepGC:使用CMS缩短响应时间,并发收集,低停顿

-XX:+UseParNewGC:并行收集新生代的垃圾

-XX:+CMSParallelRemarkEnabled:在使用 UseParNewGC 的情况下,尽量减少 mark 的时间。

-XX:+UseCMSCompactAtFullCollection:在使用 concurrent gc 的情况下,开启对老年代的压缩,使碎片减少

-XX:LargePageSizeInBytes:指定 Java heap 的分页页面大小,内存页的大小不可设置过大, 会影响 Perm 的大小。

-XX:+UseFastAccessorMethods:使用 get,set 方法转成本地代码,原始类型的快速优化。

-Djava.awt.headless=true:在linux/unix 环境下经常会碰到一个 exception 导致你在 winodws 开发环境下图片显示的好好可是在 linux/unix 下却显示不出来,因此加上这个参数以免避这样的情况出现。

10 类加载子系统

  • 类加载子系统负责从文件系统或者网络中加载Class信息,
  • 加载的类信息存放于一块称为方法区的内存空间。
  • 除了类信息外,方法区中可能还会存放运行时常量池信息,
  • 包括字符串字面量和数字量(这部分常量信息是Class文件中常量池部分的内存映射)

11 垃圾回收系统

  • 垃圾回收系统是jvm的重要组成部分,
  • 垃圾回收器 可以直接对方法区、 java堆和直接内存进行回收,
  • 其中java堆则是垃圾回收器的重点工作区域
  • 对于不在使用的垃圾对象,垃圾回收系统会在后台,查找 标识,并且释放这些不用的垃圾对象

12 执行引擎

最核心的组件,负责执行虚拟机的字节码


注意:JDK1.8 永久代被修改为元空间(Metaspace)了。


参考

可以阅读相关资料:
1. HotSpot Virtual Machine Garbage Collection Tuning Guide Release 8
2. Java虚拟机-JVM各种参数配置大全详细
3. 基于JVM(内存) 和Tomcat性能调优
4. Tomcat7优化前及优化后的性能对比
5. Tomcat 调优及 JVM 参数优化
6. JVM参数;
7. JDK 官网
8. 马士兵JVM性能调优公开课
9. 编译器中的 逃逸分析
10. JVM内存分配
11. The Structure of the Java Virtual Machine

后记

(一)理解概念,不必死记硬背,动手实验即可。 本文的内容正确性需要考究,实验出真知;
(二) 本文列举的案例,层次不够好,同时没有做很详细的分析;
(三)不同JDK版本、环境运行结果不尽相同;

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值